#ifndef UIWIN_GDI_GDIOBJ_H_
#define UIWIN_GDI_GDIOBJ_H_

#include "base/common.h"

// protect template members from windowsx.h macros
#ifdef _INC_WINDOWSX
#undef CopyRgn
#undef CreateBrush
#undef CreatePen
#undef SelectBrush
#undef SelectPen
#undef SelectFont
#undef SelectBitmap
#endif // _INC_WINDOWSX

namespace uiwin
{
	///////////////////////////////////////////////////////////////////////////////
	// CPen

	template <bool bmanaged>
	class PenT
	{
	public:
		// Data members
		HPEN pen_;

		// Constructor/destructor/operators
		PenT(HPEN pen = NULL) : pen_(pen)
		{ }

		~PenT()
		{
			if(bmanaged && pen_ != NULL)
				DeleteObject();
		}

		PenT<bmanaged>& operator =(HPEN pen)
		{
			Attach(pen);
			return *this;
		}

		void Attach(HPEN pen)
		{
			if(bmanaged && pen_ != NULL && pen_ != pen)
				::DeleteObject(pen_);
			pen_ = pen;
		}

		HPEN Detach()
		{
			HPEN pen = pen_;
			pen_ = NULL;
			return pen;
		}

		operator HPEN() const { return pen_; }

		bool IsNull() const { return (pen_ == NULL); }

		// Create methods
		HPEN CreatePen(int nPenStyle, int nWidth, COLORREF crColor)
		{
			ASSERT(pen_ == NULL);
			pen_ = ::CreatePen(nPenStyle, nWidth, crColor);
			return pen_;
		}

#ifndef _WIN32_WCE
		HPEN CreatePen(int nPenStyle, int nWidth, const LOGBRUSH* pLogBrush, int nStyleCount = 0, const DWORD* lpStyle = NULL)
		{
			ASSERT(pen_ == NULL);
			pen_ = ::ExtCreatePen(nPenStyle, nWidth, pLogBrush, nStyleCount, lpStyle);
			return pen_;
		}
#endif // !_WIN32_WCE

		HPEN CreatePenIndirect(LPLOGPEN lpLogPen)
		{
			ASSERT(pen_ == NULL);
			pen_ = ::CreatePenIndirect(lpLogPen);
			return pen_;
		}

		BOOL DeleteObject()
		{
			ASSERT(pen_ != NULL);
			BOOL bRet = ::DeleteObject(pen_);
			if(bRet)
				pen_ = NULL;
			return bRet;
		}

		// Attributes
		int GetLogPen(LOGPEN* pLogPen) const
		{
			ASSERT(pen_ != NULL);
			return ::GetObject(pen_, sizeof(LOGPEN), pLogPen);
		}

		bool GetLogPen(LOGPEN& LogPen) const
		{
			ASSERT(pen_ != NULL);
			return (::GetObject(pen_, sizeof(LOGPEN), &LogPen) == sizeof(LOGPEN));
		}

#ifndef _WIN32_WCE
		int GetExtLogPen(EXTLOGPEN* pLogPen) const
		{
			ASSERT(pen_ != NULL);
			return ::GetObject(pen_, sizeof(EXTLOGPEN), pLogPen);
		}

		bool GetExtLogPen(EXTLOGPEN& ExtLogPen) const
		{
			ASSERT(pen_ != NULL);
			return (::GetObject(pen_, sizeof(EXTLOGPEN), &ExtLogPen) == sizeof(EXTLOGPEN));
		}
#endif // !_WIN32_WCE
	};

	typedef PenT<false>   PenHandle;
	typedef PenT<true>    Pen;


	///////////////////////////////////////////////////////////////////////////////
	// CBrush

	template <bool bmanaged>
	class BrushT
	{
	public:
		// Data members
		HBRUSH brush_;

		// Constructor/destructor/operators
		BrushT(HBRUSH brush = NULL) : brush_(brush)
		{ }

		BrushT(COLORREF color) : brush_(NULL)
		{
			CreateSolidBrush(color);
		}

		~BrushT()
		{
			if(bmanaged && brush_ != NULL)
				DeleteObject();
		}

		BrushT<bmanaged>& operator =(HBRUSH brush)
		{
			Attach(brush);
			return *this;
		}

		void Attach(HBRUSH brush)
		{
			if(bmanaged && brush_ != NULL && brush_ != brush)
				::DeleteObject(brush_);
			brush_ = brush;
		}

		HBRUSH Detach()
		{
			HBRUSH brush = brush_;
			brush_ = NULL;
			return brush;
		}

		operator HBRUSH() const { return brush_; }

		bool IsNull() const { return (brush_ == NULL); }

		// Create methods
		HBRUSH CreateSolidBrush(COLORREF crColor)
		{
			ASSERT(brush_ == NULL);
			brush_ = ::CreateSolidBrush(crColor);
			return brush_;
		}

#ifndef _WIN32_WCE
		HBRUSH CreateHatcbrush(int nIndex, COLORREF crColor)
		{
			ASSERT(brush_ == NULL);
			brush_ = ::CreateHatcbrush(nIndex, crColor);
			return brush_;
		}
#endif // !_WIN32_WCE

#if !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800)
		HBRUSH CreateBrushIndirect(const LOGBRUSH* lpLogBrush)
		{
			ASSERT(brush_ == NULL);
#ifndef _WIN32_WCE
			brush_ = ::CreateBrushIndirect(lpLogBrush);
#else // CE specific
			brush_ = ATL::CreateBrushIndirect(lpLogBrush);
#endif // _WIN32_WCE
			return brush_;
		}
#endif // !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800)

		HBRUSH CreatePatternBrush(HBITMAP hBitmap)
		{
			ASSERT(brush_ == NULL);
			brush_ = ::CreatePatternBrush(hBitmap);
			return brush_;
		}

		HBRUSH CreateDIBPatternBrush(HGLOBAL hPackedDIB, UINT nUsage)
		{
			ASSERT(hPackedDIB != NULL);
			const void* lpPackedDIB = GlobalLock(hPackedDIB);
			ASSERT(lpPackedDIB != NULL);
			brush_ = ::CreateDIBPatternBrushPt(lpPackedDIB, nUsage);
			GlobalUnlock(hPackedDIB);
			return brush_;
		}

		HBRUSH CreateDIBPatternBrush(const void* lpPackedDIB, UINT nUsage)
		{
			ASSERT(brush_ == NULL);
			brush_ = ::CreateDIBPatternBrushPt(lpPackedDIB, nUsage);
			return brush_;
		}

		HBRUSH CreateSysColorBrush(int nIndex)
		{
			ASSERT(brush_ == NULL);
			brush_ = ::GetSysColorBrush(nIndex);
			return brush_;
		}

		BOOL DeleteObject()
		{
			ASSERT(brush_ != NULL);
			BOOL bRet = ::DeleteObject(brush_);
			if(bRet)
				brush_ = NULL;
			return bRet;
		}

		// Attributes
		int GetLogBrush(LOGBRUSH* pLogBrush) const
		{
			ASSERT(brush_ != NULL);
			return ::GetObject(brush_, sizeof(LOGBRUSH), pLogBrush);
		}

		bool GetLogBrush(LOGBRUSH& LogBrush) const
		{
			ASSERT(brush_ != NULL);
			return (::GetObject(brush_, sizeof(LOGBRUSH), &LogBrush) == sizeof(LOGBRUSH));
		}
	};

	typedef BrushT<false>   BrushHandle;
	typedef BrushT<true>    Brush;


	///////////////////////////////////////////////////////////////////////////////
	// CFont

	class LogFont : public LOGFONT
	{
	public:
		LogFont()
		{
			memset(this, 0, sizeof(LOGFONT));
		}

		LogFont(const LOGFONT& lf)
		{
			Copy(&lf);
		}

		LogFont(HFONT hFont)
		{
			ASSERT(::GetObjectType(hFont) == OBJ_FONT);
			::GetObject(hFont, sizeof(LOGFONT), (LOGFONT*)this);
		}

		HFONT CreateFontIndirect()
		{
			return ::CreateFontIndirect(this);
		}

		void SetBold()
		{
			lfWeight = FW_BOLD;
		}

		bool IsBold() const
		{
			return (lfWeight >= FW_BOLD);
		}

		void MakeBolder(int iScale = 1)
		{
			lfWeight += FW_BOLD * iScale;
		}

		void MakeLarger(int iScale)
		{
			if(lfHeight > 0)
				lfHeight += iScale;
			else
				lfHeight -= iScale;
		}

		void SetHeight(LONG nPointSize, HDC dc = NULL)
		{
			HDC dc1 = (dc != NULL) ? dc : ::GetDC(NULL);
			// For MM_TEXT mapping mode
			lfHeight = -::MulDiv(nPointSize, ::GetDeviceCaps(dc1, LOGPIXELSY), 72);
			if(dc == NULL)
				::ReleaseDC(NULL, dc1);
		}

		LONG GetHeight(HDC dc = NULL) const
		{
			HDC dc1 = (dc != NULL) ? dc : ::GetDC(NULL);
			// For MM_TEXT mapping mode
			LONG nPointSize = ::MulDiv(-lfHeight, 72, ::GetDeviceCaps(dc1, LOGPIXELSY));
			if(dc == NULL)
				::ReleaseDC(NULL, dc1);

			return nPointSize;
		}

		LONG GetDeciPointHeight(HDC dc = NULL) const
		{
			HDC dc1 = (dc != NULL) ? dc : ::GetDC(NULL);
#ifndef _WIN32_WCE
			POINT ptOrg = { 0, 0 };
			::DPtoLP(dc1, &ptOrg, 1);
			POINT pt = { 0, 0 };
			pt.y = abs(lfHeight) + ptOrg.y;
			::LPtoDP(dc1, &pt,1);
			LONG nDeciPoint = ::MulDiv(pt.y, 720, ::GetDeviceCaps(dc1, LOGPIXELSY));   // 72 points/inch, 10 decipoints/point
#else // CE specific
			// DP and LP are always the same on CE
			LONG nDeciPoint = ::MulDiv(abs(lfHeight), 720, ::GetDeviceCaps(dc1, LOGPIXELSY));   // 72 points/inch, 10 decipoints/point
#endif // _WIN32_WCE
			if(dc == NULL)
				::ReleaseDC(NULL, dc1);

			return nDeciPoint;
		}

		void SetHeightFromDeciPoint(LONG nDeciPtHeight, HDC dc = NULL)
		{
			HDC dc1 = (dc != NULL) ? dc : ::GetDC(NULL);
#ifndef _WIN32_WCE
			POINT pt = { 0, 0 };
			pt.y = ::MulDiv(::GetDeviceCaps(dc1, LOGPIXELSY), nDeciPtHeight, 720);   // 72 points/inch, 10 decipoints/point
			::DPtoLP(dc1, &pt, 1);
			POINT ptOrg = { 0, 0 };
			::DPtoLP(dc1, &ptOrg, 1);
			lfHeight = -abs(pt.y - ptOrg.y);
#else // CE specific
			// DP and LP are always the same on CE
			lfHeight = -abs(::MulDiv(::GetDeviceCaps(dc1, LOGPIXELSY), nDeciPtHeight, 720));   // 72 points/inch, 10 decipoints/point
#endif // _WIN32_WCE
			if(dc == NULL)
				::ReleaseDC(NULL, dc1);
		}

#ifndef _WIN32_WCE
		void SetCaptionFont()
		{
			NONCLIENTMETRICS ncm = { sizeof NONCLIENTMETRICS() };
			::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
			Copy(&ncm.lfCaptionFont);
		}

		void SetMenuFont()
		{
			NONCLIENTMETRICS ncm = { sizeof NONCLIENTMETRICS() };
			::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
			Copy(&ncm.lfMenuFont);
		}

		void SetStatusFont()
		{
			NONCLIENTMETRICS ncm = { sizeof NONCLIENTMETRICS() };
			::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
			Copy(&ncm.lfStatusFont);
		}

		void SetMessageBoxFont()
		{
			NONCLIENTMETRICS ncm = { sizeof NONCLIENTMETRICS() };
			::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
			Copy(&ncm.lfMessageFont);
		}
#endif // !_WIN32_WCE

		void Copy(const LOGFONT* pLogFont)
		{
			ASSERT(pLogFont != NULL);
			*(LOGFONT*)this = *pLogFont;
		}

		LogFont& operator =(const LogFont& src)
		{
			Copy(&src);
			return *this;
		}

		LogFont& operator =(const LOGFONT& src)
		{
			Copy(&src);
			return *this;
		}

		LogFont& operator =(HFONT hFont)
		{
			ASSERT(::GetObjectType(hFont) == OBJ_FONT);
			::GetObject(hFont, sizeof(LOGFONT), (LOGFONT*)this);
			return *this;
		}

		bool operator ==(const LOGFONT& logfont) const
		{
			return(logfont.lfHeight == lfHeight &&
				logfont.lfWidth == lfWidth &&
				logfont.lfEscapement == lfEscapement &&
				logfont.lfOrientation == lfOrientation &&
				logfont.lfWeight == lfWeight &&
				logfont.lfItalic == lfItalic &&
				logfont.lfUnderline == lfUnderline &&
				logfont.lfStrikeOut == lfStrikeOut &&
				logfont.lfCharSet == lfCharSet &&
				logfont.lfOutPrecision == lfOutPrecision &&
				logfont.lfClipPrecision == lfClipPrecision &&
				logfont.lfQuality == lfQuality &&
				logfont.lfPitchAndFamily == lfPitchAndFamily &&
				lstrcmp(logfont.lfFaceName, lfFaceName) == 0);
		}
	};


	template <bool bmanaged>
	class FontT
	{
	public:
		// Data members
		HFONT font_;

		// Constructor/destructor/operators
		FontT(HFONT hFont = NULL) : font_(hFont)
		{ }

		~FontT()
		{
			if(bmanaged && font_ != NULL)
				DeleteObject();
		}

		FontT<bmanaged>& operator =(HFONT hFont)
		{
			Attach(hFont);
			return *this;
		}

		void Attach(HFONT hFont)
		{
			if(bmanaged && font_ != NULL && font_ != hFont)
				::DeleteObject(font_);
			font_ = hFont;
		}

		HFONT Detach()
		{
			HFONT hFont = font_;
			font_ = NULL;
			return hFont;
		}

		operator HFONT() const { return font_; }

		bool IsNull() const { return (font_ == NULL); }

		// Create methods
		HFONT CreateFontIndirect(const LOGFONT* lpLogFont)
		{
			ASSERT(font_ == NULL);
			font_ = ::CreateFontIndirect(lpLogFont);
			return font_;
		}

#if !defined(_WIN32_WCE) && (_WIN32_WINNT >= 0x0500)
		HFONT CreateFontIndirectEx(CONST ENUMLOGFONTEXDV* penumlfex)
		{
			ASSERT(font_ == NULL);
			font_ = ::CreateFontIndirectEx(penumlfex);
			return font_;
		}
#endif // !defined(_WIN32_WCE) && (_WIN32_WINNT >= 0x0500)

#if !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800)
		HFONT CreateFont(int nHeight, int nWidth, int nEscapement,
			int nOrientation, int nWeight, BYTE bItalic, BYTE bUnderline,
			BYTE cStrikeOut, BYTE nCharSet, BYTE nOutPrecision,
			BYTE nClipPrecision, BYTE nQuality, BYTE nPitchAndFamily,
			LPCTSTR lpszFacename)
		{
			ASSERT(font_ == NULL);
#ifndef _WIN32_WCE
			font_ = ::CreateFont(nHeight, nWidth, nEscapement,
				nOrientation, nWeight, bItalic, bUnderline, cStrikeOut,
				nCharSet, nOutPrecision, nClipPrecision, nQuality,
				nPitchAndFamily, lpszFacename);
#else // CE specific
			font_ = ATL::CreateFont(nHeight, nWidth, nEscapement,
				nOrientation, nWeight, bItalic, bUnderline, cStrikeOut,
				nCharSet, nOutPrecision, nClipPrecision, nQuality,
				nPitchAndFamily, lpszFacename);
#endif // _WIN32_WCE
			return font_;
		}
#endif // !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800)

		HFONT CreateFont(LPCTSTR lpszFaceName, int nSize, bool bBold = false, bool bItalic = false)
		{
			LogFont logfont;

			logfont.lfCharSet = DEFAULT_CHARSET;
			//logfont.lfWidth = nSize;
			logfont.lfHeight = -nSize;
			_tcscpy_s(logfont.lfFaceName, _countof(logfont.lfFaceName), lpszFaceName);

			if(bBold)
				logfont.lfWeight = FW_BOLD;
			if(bItalic)
				logfont.lfItalic = (BYTE)TRUE;

			font_ = logfont.CreateFontIndirect();

			return font_;
		}

		HFONT CreatePointFont(int nPointSize, LPCTSTR lpszFaceName, HDC dc = NULL, bool bBold = false, bool bItalic = false)
		{
			LOGFONT logFont = { 0 };
			logFont.lfCharSet = DEFAULT_CHARSET;
			logFont.lfHeight = nPointSize;
			_tcscpy_s(logFont.lfFaceName, _countof(logFont.lfFaceName), lpszFaceName);

			if(bBold)
				logFont.lfWeight = FW_BOLD;
			if(bItalic)
				logFont.lfItalic = (BYTE)TRUE;

			return CreatePointFontIndirect(&logFont, dc);
		}

		HFONT CreatePointFontIndirect(const LOGFONT* lpLogFont, HDC dc = NULL)
		{
			HDC dc1 = (dc != NULL) ? dc : ::GetDC(NULL);

			// convert nPointSize to logical units based on dc
			LOGFONT logFont = *lpLogFont;
#ifndef _WIN32_WCE
			POINT pt = { 0, 0 };
			pt.y = ::MulDiv(::GetDeviceCaps(dc1, LOGPIXELSY), logFont.lfHeight, 720);   // 72 points/inch, 10 decipoints/point
			::DPtoLP(dc1, &pt, 1);
			POINT ptOrg = { 0, 0 };
			::DPtoLP(dc1, &ptOrg, 1);
			logFont.lfHeight = -abs(pt.y - ptOrg.y);
#else // CE specific
			// DP and LP are always the same on CE
			logFont.lfHeight = -abs(::MulDiv(::GetDeviceCaps(dc1, LOGPIXELSY), logFont.lfHeight, 720));   // 72 points/inch, 10 decipoints/point
#endif // _WIN32_WCE

			if(dc == NULL)
				::ReleaseDC(NULL, dc1);

			return CreateFontIndirect(&logFont);
		}

		BOOL DeleteObject()
		{
			ASSERT(font_ != NULL);
			BOOL bRet = ::DeleteObject(font_);
			if(bRet)
				font_ = NULL;
			return bRet;
		}

		// Attributes
		int GetLogFont(LOGFONT* pLogFont) const
		{
			ASSERT(font_ != NULL);
			return ::GetObject(font_, sizeof(LOGFONT), pLogFont);
		}

		bool GetLogFont(LOGFONT& LogFont) const
		{
			ASSERT(font_ != NULL);
			return (::GetObject(font_, sizeof(LOGFONT), &LogFont) == sizeof(LOGFONT));
		}
	};

	typedef FontT<false>   FontHandle;
	typedef FontT<true>    Font;


	///////////////////////////////////////////////////////////////////////////////
	// Bitmap

	template <bool bmanaged>
	class BitmapT
	{
	public:
		// Data members
		HBITMAP bitmap_;

		// Constructor/destructor/operators
		BitmapT(HBITMAP hBitmap = NULL) : bitmap_(hBitmap)
		{ }

		~BitmapT()
		{
			if(bmanaged && bitmap_ != NULL)
				DeleteObject();
		}

		BitmapT<bmanaged>& operator =(HBITMAP hBitmap)
		{
			Attach(hBitmap);
			return *this;
		}

		void Attach(HBITMAP hBitmap)
		{
			if(bmanaged && bitmap_ != NULL&& bitmap_ != hBitmap)
				::DeleteObject(bitmap_);
			bitmap_ = hBitmap;
		}

		HBITMAP Detach()
		{
			HBITMAP hBitmap = bitmap_;
			bitmap_ = NULL;
			return hBitmap;
		}

		operator HBITMAP() const { return bitmap_; }

		bool IsNull() const { return (bitmap_ == NULL); }

		// Create and load methods
// 		HBITMAP LoadBitmap(ATL::_U_STRINGorID bitmap)
// 		{
// 			ASSERT(bitmap_ == NULL);
// 			bitmap_ = ::LoadBitmap(ModuleHelper::GetResourceInstance(), bitmap.m_lpstr);
// 			return bitmap_;
// 		}

		HBITMAP LoadOEMBitmap(UINT nIDBitmap) // for OBM_/OCR_/OIC_
		{
			ASSERT(bitmap_ == NULL);
			bitmap_ = ::LoadBitmap(NULL, MAKEINTRESOURCE(nIDBitmap));
			return bitmap_;
		}

#ifndef _WIN32_WCE
// 		HBITMAP LoadMappedBitmap(UINT nIDBitmap, UINT nFlags = 0, LPCOLORMAP lpColorMap = NULL, int nMapSize = 0)
// 		{
// 			ASSERT(bitmap_ == NULL);
// 			bitmap_ = ::CreateMappedBitmap(ModuleHelper::GetResourceInstance(), nIDBitmap, (WORD)nFlags, lpColorMap, nMapSize);
// 			return bitmap_;
// 		}
#endif // !_WIN32_WCE

		HBITMAP CreateBitmap(int nWidth, int nHeight, UINT nPlanes, UINT nBitsPerPixel, const void* lpBits)
		{
			ASSERT(bitmap_ == NULL);
			bitmap_ = ::CreateBitmap(nWidth, nHeight, nPlanes, nBitsPerPixel, lpBits);
			return bitmap_;
		}

#ifndef _WIN32_WCE
		HBITMAP CreateBitmapIndirect(LPBITMAP lpBitmap)
		{
			ASSERT(bitmap_ == NULL);
			bitmap_ = ::CreateBitmapIndirect(lpBitmap);
			return bitmap_;
		}
#endif // !_WIN32_WCE

		HBITMAP CreateCompatibleBitmap(HDC dc, int nWidth, int nHeight)
		{
			ASSERT(bitmap_ == NULL);
			bitmap_ = ::CreateCompatibleBitmap(dc, nWidth, nHeight);
			return bitmap_;
		}

#ifndef _WIN32_WCE
		HBITMAP CreateDiscardableBitmap(HDC dc, int nWidth, int nHeight)
		{
			ASSERT(bitmap_ == NULL);
			bitmap_ = ::CreateDiscardableBitmap(dc, nWidth, nHeight);
			return bitmap_;
		}
#endif // !_WIN32_WCE

		BOOL DeleteObject()
		{
			ASSERT(bitmap_ != NULL);
			BOOL bRet = ::DeleteObject(bitmap_);
			if(bRet)
				bitmap_ = NULL;
			return bRet;
		}

		// Attributes
		int GetBitmap(BITMAP* pBitMap) const
		{
			ASSERT(bitmap_ != NULL);
			return ::GetObject(bitmap_, sizeof(BITMAP), pBitMap);
		}

		bool GetBitmap(BITMAP& bm) const
		{
			ASSERT(bitmap_ != NULL);
			return (::GetObject(bitmap_, sizeof(BITMAP), &bm) == sizeof(BITMAP));
		}

		bool GetSize(SIZE& size) const
		{
			ASSERT(bitmap_ != NULL);
			BITMAP bm = { 0 };
			if(!GetBitmap(&bm))
				return false;
			size.cx = bm.bmWidth;
			size.cy = bm.bmHeight;
			return true;
		}

#ifndef _WIN32_WCE
		DWORD GetBitmapBits(DWORD dwCount, LPVOID lpBits) const
		{
			ASSERT(bitmap_ != NULL);
			return ::GetBitmapBits(bitmap_, dwCount, lpBits);
		}
#endif // !_WIN32_WCE

#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 410)
		DWORD SetBitmapBits(DWORD dwCount, const void* lpBits)
		{
			ASSERT(bitmap_ != NULL);
			return ::SetBitmapBits(bitmap_, dwCount, lpBits);
		}
#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 410)

#ifndef _WIN32_WCE
		BOOL GetBitmapDimension(LPSIZE lpSize) const
		{
			ASSERT(bitmap_ != NULL);
			return ::GetBitmapDimensionEx(bitmap_, lpSize);
		}

		BOOL SetBitmapDimension(int nWidth, int nHeight, LPSIZE lpSize = NULL)
		{
			ASSERT(bitmap_ != NULL);
			return ::SetBitmapDimensionEx(bitmap_, nWidth, nHeight, lpSize);
		}

		// DIB support
		HBITMAP CreateDIBitmap(HDC dc, CONST BITMAPINFOHEADER* lpbmih, DWORD dwInit, CONST VOID* lpbInit, CONST BITMAPINFO* lpbmi, UINT uColorUse)
		{
			ASSERT(bitmap_ == NULL);
			bitmap_ = ::CreateDIBitmap(dc, lpbmih, dwInit, lpbInit, lpbmi, uColorUse);
			return bitmap_;
		}
#endif // !_WIN32_WCE

		HBITMAP CreateDIBSection(HDC dc, CONST BITMAPINFO* lpbmi, UINT uColorUse, VOID** ppvBits, HANDLE hSection, DWORD dwOffset)
		{
			ASSERT(bitmap_ == NULL);
			bitmap_ = ::CreateDIBSection(dc, lpbmi, uColorUse, ppvBits, hSection, dwOffset);
			return bitmap_;
		}

#ifndef _WIN32_WCE
		int GetDIBits(HDC dc, UINT uStartScan, UINT cScanLines,  LPVOID lpvBits, LPBITMAPINFO lpbmi, UINT uColorUse) const
		{
			ASSERT(bitmap_ != NULL);
			return ::GetDIBits(dc, bitmap_, uStartScan, cScanLines,  lpvBits, lpbmi, uColorUse);
		}

		int SetDIBits(HDC dc, UINT uStartScan, UINT cScanLines, CONST VOID* lpvBits, CONST BITMAPINFO* lpbmi, UINT uColorUse)
		{
			ASSERT(bitmap_ != NULL);
			return ::SetDIBits(dc, bitmap_, uStartScan, cScanLines, lpvBits, lpbmi, uColorUse);
		}
#endif // !_WIN32_WCE
	};

	typedef BitmapT<false>   BitmapHandle;
	typedef BitmapT<true>    Bitmap;


	///////////////////////////////////////////////////////////////////////////////
	// CPalette

	template <bool bmanaged>
	class PaletteT
	{
	public:
		// Data members
		HPALETTE palette_;

		// Constructor/destructor/operators
		PaletteT(HPALETTE hPalette = NULL) : palette_(hPalette)
		{ }

		~PaletteT()
		{
			if(bmanaged && palette_ != NULL)
				DeleteObject();
		}

		PaletteT<bmanaged>& operator =(HPALETTE hPalette)
		{
			Attach(hPalette);
			return *this;
		}

		void Attach(HPALETTE hPalette)
		{
			if(bmanaged && palette_ != NULL && palette_ != hPalette)
				::DeleteObject(palette_);
			palette_ = hPalette;
		}

		HPALETTE Detach()
		{
			HPALETTE hPalette = palette_;
			palette_ = NULL;
			return hPalette;
		}

		operator HPALETTE() const { return palette_; }

		bool IsNull() const { return (palette_ == NULL); }

		// Create methods
		HPALETTE CreatePalette(LPLOGPALETTE lpLogPalette)
		{
			ASSERT(palette_ == NULL);
			palette_ = ::CreatePalette(lpLogPalette);
			return palette_;
		}

#ifndef _WIN32_WCE
		HPALETTE CreateHalftonePalette(HDC dc)
		{
			ASSERT(palette_ == NULL);
			ASSERT(dc != NULL);
			palette_ = ::CreateHalftonePalette(dc);
			return palette_;
		}
#endif // !_WIN32_WCE

		BOOL DeleteObject()
		{
			ASSERT(palette_ != NULL);
			BOOL bRet = ::DeleteObject(palette_);
			if(bRet)
				palette_ = NULL;
			return bRet;
		}

		// Attributes
		int GetEntryCount() const
		{
			ASSERT(palette_ != NULL);
			WORD nEntries = 0;
			::GetObject(palette_, sizeof(WORD), &nEntries);
			return (int)nEntries;
		}

		UINT GetPaletteEntries(UINT nStartIndex, UINT nNumEntries, LPPALETTEENTRY lpPaletteColors) const
		{
			ASSERT(palette_ != NULL);
			return ::GetPaletteEntries(palette_, nStartIndex, nNumEntries, lpPaletteColors);
		}

		UINT SetPaletteEntries(UINT nStartIndex, UINT nNumEntries, LPPALETTEENTRY lpPaletteColors)
		{
			ASSERT(palette_ != NULL);
			return ::SetPaletteEntries(palette_, nStartIndex, nNumEntries, lpPaletteColors);
		}

		// Operations
#ifndef _WIN32_WCE
		void AnimatePalette(UINT nStartIndex, UINT nNumEntries, LPPALETTEENTRY lpPaletteColors)
		{
			ASSERT(palette_ != NULL);
			::AnimatePalette(palette_, nStartIndex, nNumEntries, lpPaletteColors);
		}

		BOOL ResizePalette(UINT nNumEntries)
		{
			ASSERT(palette_ != NULL);
			return ::ResizePalette(palette_, nNumEntries);
		}
#endif // !_WIN32_WCE

		UINT GetNearestPaletteIndex(COLORREF crColor) const
		{
			ASSERT(palette_ != NULL);
			return ::GetNearestPaletteIndex(palette_, crColor);
		}
	};

	typedef PaletteT<false>   CPaletteHandle;
	typedef PaletteT<true>    CPalette;


	///////////////////////////////////////////////////////////////////////////////
	// CRgn

	template <bool bmanaged>
	class RgnT
	{
	public:
		// Data members
		HRGN rgn_;

		// Constructor/destructor/operators
		RgnT(HRGN rgn = NULL) : rgn_(rgn)
		{ }

		~RgnT()
		{
			if(bmanaged && rgn_ != NULL)
				DeleteObject();
		}

		RgnT<bmanaged>& operator =(HRGN rgn)
		{
			Attach(rgn);
			return *this;
		}

		void Attach(HRGN rgn)
		{
			if(bmanaged && rgn_ != NULL && rgn_ != rgn)
				::DeleteObject(rgn_);
			rgn_ = rgn;
		}

		HRGN Detach()
		{
			HRGN rgn = rgn_;
			rgn_ = NULL;
			return rgn;
		}

		operator HRGN() const { return rgn_; }

		bool IsNull() const { return (rgn_ == NULL); }

		// Create methods
		HRGN CreateRectRgn(int x1, int y1, int x2, int y2)
		{
			ASSERT(rgn_ == NULL);
			rgn_ = ::CreateRectRgn(x1, y1, x2, y2);
			return rgn_;
		}

		HRGN CreateRectRgnIndirect(LPCRECT lpRect)
		{
			ASSERT(rgn_ == NULL);
			rgn_ = ::CreateRectRgnIndirect(lpRect);
			return rgn_;
		}

#ifndef _WIN32_WCE
		HRGN CreateEllipticRgn(int x1, int y1, int x2, int y2)
		{
			ASSERT(rgn_ == NULL);
			rgn_ = ::CreateEllipticRgn(x1, y1, x2, y2);
			return rgn_;
		}

		HRGN CreateEllipticRgnIndirect(LPCRECT lpRect)
		{
			ASSERT(rgn_ == NULL);
			rgn_ = ::CreateEllipticRgnIndirect(lpRect);
			return rgn_;
		}

		HRGN CreatePolygonRgn(LPPOINT lpPoints, int nCount, int nMode)
		{
			ASSERT(rgn_ == NULL);
			rgn_ = ::CreatePolygonRgn(lpPoints, nCount, nMode);
			return rgn_;
		}

		HRGN CreatePolyPolygonRgn(LPPOINT lpPoints, LPINT lpPolyCounts, int nCount, int nPolyFillMode)
		{
			ASSERT(rgn_ == NULL);
			rgn_ = ::CreatePolyPolygonRgn(lpPoints, lpPolyCounts, nCount, nPolyFillMode);
			return rgn_;
		}

		HRGN CreateRoundRectRgn(int x1, int y1, int x2, int y2, int x3, int y3)
		{
			ASSERT(rgn_ == NULL);
			rgn_ = ::CreateRoundRectRgn(x1, y1, x2, y2, x3, y3);
			return rgn_;
		}

		HRGN CreateFromPath(HDC dc)
		{
			ASSERT(rgn_ == NULL);
			ASSERT(dc != NULL);
			rgn_ = ::PathToRegion(dc);
			return rgn_;
		}

		HRGN CreateFromData(const XFORM* lpXForm, int nCount, const RGNDATA* pRgnData)
		{
			ASSERT(rgn_ == NULL);
			rgn_ = ::ExtCreateRegion(lpXForm, nCount, pRgnData);
			return rgn_;
		}
#endif // !_WIN32_WCE

		BOOL DeleteObject()
		{
			ASSERT(rgn_ != NULL);
			BOOL bRet = ::DeleteObject(rgn_);
			if(bRet)
				rgn_ = NULL;
			return bRet;
		}

		// Operations
		void SetRectRgn(int x1, int y1, int x2, int y2)
		{
			ASSERT(rgn_ != NULL);
			::SetRectRgn(rgn_, x1, y1, x2, y2);
		}

		void SetRectRgn(LPCRECT lpRect)
		{
			ASSERT(rgn_ != NULL);
			::SetRectRgn(rgn_, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom);
		}

		int CombineRgn(HRGN rgnSrc1, HRGN rgnSrc2, int nCombineMode)
		{
			ASSERT(rgn_ != NULL);
			return ::CombineRgn(rgn_, rgnSrc1, rgnSrc2, nCombineMode);
		}

		int CombineRgn(HRGN rgnSrc, int nCombineMode)
		{
			ASSERT(rgn_ != NULL);
			return ::CombineRgn(rgn_, rgn_, rgnSrc, nCombineMode);
		}

		int CopyRgn(HRGN rgnSrc)
		{
			ASSERT(rgn_ != NULL);
			return ::CombineRgn(rgn_, rgnSrc, NULL, RGN_COPY);
		}

		BOOL EqualRgn(HRGN rgn) const
		{
			ASSERT(rgn_ != NULL);
			return ::EqualRgn(rgn_, rgn);
		}

		int OffsetRgn(int x, int y)
		{
			ASSERT(rgn_ != NULL);
			return ::OffsetRgn(rgn_, x, y);
		}

		int OffsetRgn(POINT point)
		{
			ASSERT(rgn_ != NULL);
			return ::OffsetRgn(rgn_, point.x, point.y);
		}

		int GetRgnBox(LPRECT lpRect) const
		{
			ASSERT(rgn_ != NULL);
			return ::GetRgnBox(rgn_, lpRect);
		}

		BOOL PtInRegion(int x, int y) const
		{
			ASSERT(rgn_ != NULL);
			return ::PtInRegion(rgn_, x, y);
		}

		BOOL PtInRegion(POINT point) const
		{
			ASSERT(rgn_ != NULL);
			return ::PtInRegion(rgn_, point.x, point.y);
		}

		BOOL RectInRegion(LPCRECT lpRect) const
		{
			ASSERT(rgn_ != NULL);
			return ::RectInRegion(rgn_, lpRect);
		}

		int GetRegionData(LPRGNDATA lpRgnData, int nDataSize) const
		{
			ASSERT(rgn_ != NULL);
			return (int)::GetRegionData(rgn_, nDataSize, lpRgnData);
		}
	};

	typedef RgnT<false>   RgnHandle;
	typedef RgnT<true>    Rgn;


	///////////////////////////////////////////////////////////////////////////////
	// CDC - The device context class

	template <bool bmanaged>
	class DCT
	{
	public:
		// Data members
		HDC hdc_;

		// Constructor/destructor/operators
		DCT(HDC dc = NULL) : hdc_(dc) { }

		~DCT()
		{
			if(bmanaged && hdc_ != NULL)
				::DeleteDC(Detach());
		}

		DCT<bmanaged>& operator =(HDC dc)
		{
			Attach(dc);
			return *this;
		}

		void Attach(HDC dc)
		{
			if(bmanaged && hdc_ != NULL && hdc_ != dc)
				::DeleteDC(hdc_);
			hdc_ = dc;
		}

		HDC Detach()
		{
			HDC dc = hdc_;
			hdc_ = NULL;
			return dc;
		}

		operator HDC() const { return hdc_; }

		bool IsNull() const { return (hdc_ == NULL); }

		// Operations
#ifndef _WIN32_WCE
		HWND WindowFromDC() const
		{
			ASSERT(hdc_ != NULL);
			return ::WindowFromDC(hdc_);
		}
#endif // !_WIN32_WCE

		PenHandle GetCurrentPen() const
		{
			ASSERT(hdc_ != NULL);
			return PenHandle((HPEN)::GetCurrentObject(hdc_, OBJ_PEN));
		}

		BrushHandle GetCurrentBrush() const
		{
			ASSERT(hdc_ != NULL);
			return BrushHandle((HBRUSH)::GetCurrentObject(hdc_, OBJ_BRUSH));
		}

		CPaletteHandle GetCurrentPalette() const
		{
			ASSERT(hdc_ != NULL);
			return CPaletteHandle((HPALETTE)::GetCurrentObject(hdc_, OBJ_PAL));
		}

		FontHandle GetCurrentFont() const
		{
			ASSERT(hdc_ != NULL);
			return FontHandle((HFONT)::GetCurrentObject(hdc_, OBJ_FONT));
		}

		BitmapHandle GetCurrentBitmap() const
		{
			ASSERT(hdc_ != NULL);
			return BitmapHandle((HBITMAP)::GetCurrentObject(hdc_, OBJ_BITMAP));
		}

		HDC CreateDC(LPCTSTR lpszDriverName, LPCTSTR lpszDeviceName, LPCTSTR lpszOutput, const DEVMODE* lpInitData)
		{
			ASSERT(hdc_ == NULL);
			hdc_ = ::CreateDC(lpszDriverName, lpszDeviceName, lpszOutput, lpInitData);
			return hdc_;
		}

		HDC CreateCompatibleDC(HDC dc = NULL)
		{
			ASSERT(hdc_ == NULL);
			hdc_ = ::CreateCompatibleDC(dc);
			return hdc_;
		}

		BOOL DeleteDC()
		{
			if(hdc_ == NULL)
				return FALSE;
			BOOL bRet = ::DeleteDC(hdc_);
			if(bRet)
				hdc_ = NULL;
			return bRet;
		}

		// Device-Context Functions
		int SaveDC()
		{
			ASSERT(hdc_ != NULL);
			return ::SaveDC(hdc_);
		}

		BOOL RestoreDC(int nSavedDC)
		{
			ASSERT(hdc_ != NULL);
			return ::RestoreDC(hdc_, nSavedDC);
		}

		int GetDeviceCaps(int nIndex) const
		{
			ASSERT(hdc_ != NULL);
			return ::GetDeviceCaps(hdc_, nIndex);
		}

#ifndef _WIN32_WCE
		UINT SetBoundsRect(LPCRECT lpRectBounds, UINT flags)
		{
			ASSERT(hdc_ != NULL);
			return ::SetBoundsRect(hdc_, lpRectBounds, flags);
		}

		UINT GetBoundsRect(LPRECT lpRectBounds, UINT flags) const
		{
			ASSERT(hdc_ != NULL);
			return ::GetBoundsRect(hdc_, lpRectBounds, flags);
		}

		BOOL ResetDC(const DEVMODE* lpDevMode)
		{
			ASSERT(hdc_ != NULL);
			return ::ResetDC(hdc_, lpDevMode) != NULL;
		}

		// Drawing-Tool Functions
		BOOL GetBrushOrg(LPPOINT lpPoint) const
		{
			ASSERT(hdc_ != NULL);
			return ::GetBrushOrgEx(hdc_, lpPoint);
		}
#endif // !_WIN32_WCE

		BOOL SetBrushOrg(int x, int y, LPPOINT lpPoint = NULL)
		{
			ASSERT(hdc_ != NULL);
			return ::SetBrushOrgEx(hdc_, x, y, lpPoint);
		}

		BOOL SetBrushOrg(POINT point, LPPOINT lpPointRet = NULL)
		{
			ASSERT(hdc_ != NULL);
			return ::SetBrushOrgEx(hdc_, point.x, point.y, lpPointRet);
		}

#ifndef _WIN32_WCE
		int EnumObjects(int nObjectType, int (CALLBACK* lpfn)(LPVOID, LPARAM), LPARAM lpData)
		{
			ASSERT(hdc_ != NULL);
#ifdef STRICT
			return ::EnumObjects(hdc_, nObjectType, (GOBJENUMPROC)lpfn, lpData);
#else
			return ::EnumObjects(hdc_, nObjectType, (GOBJENUMPROC)lpfn, (LPVOID)lpData);
#endif
		}
#endif // !_WIN32_WCE

		// Type-safe selection helpers
		HPEN SelectPen(HPEN pen)
		{
			ASSERT(hdc_ != NULL);
#ifndef _WIN32_WCE
			ASSERT(pen == NULL || ::GetObjectType(pen) == OBJ_PEN || ::GetObjectType(pen) == OBJ_EXTPEN);
#else // CE specific
			ASSERT(pen == NULL || ::GetObjectType(pen) == OBJ_PEN);
#endif // _WIN32_WCE
			return (HPEN)::SelectObject(hdc_, pen);
		}

		HBRUSH SelectBrush(HBRUSH brush)
		{
			ASSERT(hdc_ != NULL);
			ASSERT(brush == NULL || ::GetObjectType(brush) == OBJ_BRUSH);
			return (HBRUSH)::SelectObject(hdc_, brush);
		}

		HFONT SelectFont(HFONT hFont)
		{
			ASSERT(hdc_ != NULL);
			ASSERT(hFont == NULL || ::GetObjectType(hFont) == OBJ_FONT);
			return (HFONT)::SelectObject(hdc_, hFont);
		}

		HBITMAP SelectBitmap(HBITMAP hBitmap)
		{
			ASSERT(hdc_ != NULL);
			ASSERT(hBitmap == NULL || ::GetObjectType(hBitmap) == OBJ_BITMAP);
			return (HBITMAP)::SelectObject(hdc_, hBitmap);
		}

		int SelectRgn(HRGN rgn)       // special return for regions
		{
			ASSERT(hdc_ != NULL);
			ASSERT(rgn == NULL || ::GetObjectType(rgn) == OBJ_REGION);
			return PtrToInt(::SelectObject(hdc_, rgn));
		}

		// Type-safe selection helpers for stock objects
		HPEN SelectStockPen(int nPen)
		{
			ASSERT(hdc_ != NULL);
#if (_WIN32_WINNT >= 0x0500)
			ASSERT(nPen == WHITE_PEN || nPen == BLACK_PEN || nPen == NULL_PEN || nPen == DC_PEN);
#else
			ASSERT(nPen == WHITE_PEN || nPen == BLACK_PEN || nPen == NULL_PEN);
#endif // !(_WIN32_WINNT >= 0x0500)
			return SelectPen((HPEN)::GetStockObject(nPen));
		}

		HBRUSH SelectStockBrush(int nBrush)
		{
#if (_WIN32_WINNT >= 0x0500)
			ASSERT((nBrush >= WHITE_BRUSH && nBrush <= HOLLOW_BRUSH) || nBrush == DC_BRUSH);
#else
			ASSERT(nBrush >= WHITE_BRUSH && nBrush <= HOLLOW_BRUSH);
#endif // !(_WIN32_WINNT >= 0x0500)
			return SelectBrush((HBRUSH)::GetStockObject(nBrush));
		}

		HFONT SelectStockFont(int nFont)
		{
#ifndef _WIN32_WCE
			ASSERT((nFont >= OEM_FIXED_FONT && nFont <= SYSTEM_FIXED_FONT) || nFont == DEFAULT_GUI_FONT);
#else // CE specific
			ASSERT(nFont == SYSTEM_FONT);
#endif // _WIN32_WCE
			return SelectFont((HFONT)::GetStockObject(nFont));
		}

		HPALETTE SelectStockPalette(int nPalette, BOOL bForceBackground)
		{
			ASSERT(nPalette == DEFAULT_PALETTE); // the only one supported
			return SelectPalette((HPALETTE)::GetStockObject(nPalette), bForceBackground);
		}

		// Color and Color Palette Functions
		COLORREF GetNearestColor(COLORREF crColor) const
		{
			ASSERT(hdc_ != NULL);
			return ::GetNearestColor(hdc_, crColor);
		}

		HPALETTE SelectPalette(HPALETTE hPalette, BOOL bForceBackground)
		{
			ASSERT(hdc_ != NULL);

			return ::SelectPalette(hdc_, hPalette, bForceBackground);
		}

		UINT RealizePalette()
		{
			ASSERT(hdc_ != NULL);
			return ::RealizePalette(hdc_);
		}

#ifndef _WIN32_WCE
		void UpdateColors()
		{
			ASSERT(hdc_ != NULL);
			::UpdateColors(hdc_);
		}
#endif // !_WIN32_WCE

		// Drawing-Attribute Functions
		COLORREF GetBkColor() const
		{
			ASSERT(hdc_ != NULL);
			return ::GetBkColor(hdc_);
		}

		int GetBkMode() const
		{
			ASSERT(hdc_ != NULL);
			return ::GetBkMode(hdc_);
		}

#ifndef _WIN32_WCE
		int GetPolyFillMode() const
		{
			ASSERT(hdc_ != NULL);
			return ::GetPolyFillMode(hdc_);
		}

		int GetROP2() const
		{
			ASSERT(hdc_ != NULL);
			return ::GetROP2(hdc_);
		}

		int GetStretchBltMode() const
		{
			ASSERT(hdc_ != NULL);
			return ::GetStretchBltMode(hdc_);
		}
#endif // !_WIN32_WCE

		COLORREF GetTextColor() const
		{
			ASSERT(hdc_ != NULL);
			return ::GetTextColor(hdc_);
		}

		COLORREF SetBkColor(COLORREF crColor)
		{
			ASSERT(hdc_ != NULL);
			return ::SetBkColor(hdc_, crColor);
		}

		int SetBkMode(int nBkMode)
		{
			ASSERT(hdc_ != NULL);
			return ::SetBkMode(hdc_, nBkMode);
		}

#ifndef _WIN32_WCE
		int SetPolyFillMode(int nPolyFillMode)
		{
			ASSERT(hdc_ != NULL);
			return ::SetPolyFillMode(hdc_, nPolyFillMode);
		}
#endif // !_WIN32_WCE

		int SetROP2(int nDrawMode)
		{
			ASSERT(hdc_ != NULL);
			return ::SetROP2(hdc_, nDrawMode);
		}

#ifndef _WIN32_WCE
		int SetStretchBltMode(int nStretchMode)
		{
			ASSERT(hdc_ != NULL);
			return ::SetStretchBltMode(hdc_, nStretchMode);
		}
#endif // !_WIN32_WCE

		COLORREF SetTextColor(COLORREF crColor)
		{
			ASSERT(hdc_ != NULL);
			return ::SetTextColor(hdc_, crColor);
		}

#ifndef _WIN32_WCE
		BOOL GetColorAdjustment(LPCOLORADJUSTMENT lpColorAdjust) const
		{
			ASSERT(hdc_ != NULL);
			return ::GetColorAdjustment(hdc_, lpColorAdjust);
		}

		BOOL SetColorAdjustment(const COLORADJUSTMENT* lpColorAdjust)
		{
			ASSERT(hdc_ != NULL);
			return ::SetColorAdjustment(hdc_, lpColorAdjust);
		}

		// Mapping Functions
		int GetMapMode() const
		{
			ASSERT(hdc_ != NULL);
			return ::GetMapMode(hdc_);
		}

		BOOL GetViewportOrg(LPPOINT lpPoint) const
		{
			ASSERT(hdc_ != NULL);
			return ::GetViewportOrgEx(hdc_, lpPoint);
		}

		int SetMapMode(int nMapMode)
		{
			ASSERT(hdc_ != NULL);
			return ::SetMapMode(hdc_, nMapMode);
		}
#endif // !_WIN32_WCE

		// Viewport Origin
		BOOL SetViewportOrg(int x, int y, LPPOINT lpPoint = NULL)
		{
			ASSERT(hdc_ != NULL);
			return ::SetViewportOrgEx(hdc_, x, y, lpPoint);
		}

		BOOL SetViewportOrg(POINT point, LPPOINT lpPointRet = NULL)
		{
			ASSERT(hdc_ != NULL);
			return SetViewportOrg(point.x, point.y, lpPointRet);
		}

#ifndef _WIN32_WCE
		BOOL OffsetViewportOrg(int nWidth, int nHeight, LPPOINT lpPoint = NULL)
		{
			ASSERT(hdc_ != NULL);
			return ::OffsetViewportOrgEx(hdc_, nWidth, nHeight, lpPoint);
		}

		// Viewport Extent
		BOOL GetViewportExt(LPSIZE lpSize) const
		{
			ASSERT(hdc_ != NULL);
			return ::GetViewportExtEx(hdc_, lpSize);
		}

		BOOL SetViewportExt(int x, int y, LPSIZE lpSize = NULL)
		{
			ASSERT(hdc_ != NULL);
			return ::SetViewportExtEx(hdc_, x, y, lpSize);
		}

		BOOL SetViewportExt(SIZE size, LPSIZE lpSizeRet = NULL)
		{
			ASSERT(hdc_ != NULL);
			return SetViewportExt(size.cx, size.cy, lpSizeRet);
		}

		BOOL ScaleViewportExt(int xNum, int xDenom, int yNum, int yDenom, LPSIZE lpSize = NULL)
		{
			ASSERT(hdc_ != NULL);
			return ::ScaleViewportExtEx(hdc_, xNum, xDenom, yNum, yDenom, lpSize);
		}
#endif // !_WIN32_WCE

		// Window Origin
#ifndef _WIN32_WCE
		BOOL GetWindowOrg(LPPOINT lpPoint) const
		{
			ASSERT(hdc_ != NULL);
			return ::GetWindowOrgEx(hdc_, lpPoint);
		}

		BOOL SetWindowOrg(int x, int y, LPPOINT lpPoint = NULL)
		{
			ASSERT(hdc_ != NULL);
			return ::SetWindowOrgEx(hdc_, x, y, lpPoint);
		}

		BOOL SetWindowOrg(POINT point, LPPOINT lpPointRet = NULL)
		{
			ASSERT(hdc_ != NULL);
			return SetWindowOrg(point.x, point.y, lpPointRet);
		}

		BOOL OffsetWindowOrg(int nWidth, int nHeight, LPPOINT lpPoint = NULL)
		{
			ASSERT(hdc_ != NULL);
			return ::OffsetWindowOrgEx(hdc_, nWidth, nHeight, lpPoint);
		}

		// Window extent
		BOOL GetWindowExt(LPSIZE lpSize) const
		{
			ASSERT(hdc_ != NULL);
			return ::GetWindowExtEx(hdc_, lpSize);
		}

		BOOL SetWindowExt(int x, int y, LPSIZE lpSize = NULL)
		{
			ASSERT(hdc_ != NULL);
			return ::SetWindowExtEx(hdc_, x, y, lpSize);
		}

		BOOL SetWindowExt(SIZE size, LPSIZE lpSizeRet = NULL)
		{
			ASSERT(hdc_ != NULL);
			return SetWindowExt(size.cx, size.cy, lpSizeRet);
		}

		BOOL ScaleWindowExt(int xNum, int xDenom, int yNum, int yDenom, LPSIZE lpSize = NULL)
		{
			ASSERT(hdc_ != NULL);
			return ::ScaleWindowExtEx(hdc_, xNum, xDenom, yNum, yDenom, lpSize);
		}

		// Coordinate Functions
		BOOL DPtoLP(LPPOINT lpPoints, int nCount = 1) const
		{
			ASSERT(hdc_ != NULL);
			return ::DPtoLP(hdc_, lpPoints, nCount);
		}

		BOOL DPtoLP(LPRECT lpRect) const
		{
			ASSERT(hdc_ != NULL);
			return ::DPtoLP(hdc_, (LPPOINT)lpRect, 2);
		}

		BOOL DPtoLP(LPSIZE lpSize) const
		{
			SIZE sizeWinExt = { 0, 0 };
			if(!GetWindowExt(&sizeWinExt))
				return FALSE;
			SIZE sizeVpExt = { 0, 0 };
			if(!GetViewportExt(&sizeVpExt))
				return FALSE;
			lpSize->cx = ::MulDiv(lpSize->cx, abs(sizeWinExt.cx), abs(sizeVpExt.cx));
			lpSize->cy = ::MulDiv(lpSize->cy, abs(sizeWinExt.cy), abs(sizeVpExt.cy));
			return TRUE;
		}

		BOOL LPtoDP(LPPOINT lpPoints, int nCount = 1) const
		{
			ASSERT(hdc_ != NULL);
			return ::LPtoDP(hdc_, lpPoints, nCount);
		}

		BOOL LPtoDP(LPRECT lpRect) const
		{
			ASSERT(hdc_ != NULL);
			return ::LPtoDP(hdc_, (LPPOINT)lpRect, 2);
		}

		BOOL LPtoDP(LPSIZE lpSize) const
		{
			SIZE sizeWinExt = { 0, 0 };
			if(!GetWindowExt(&sizeWinExt))
				return FALSE;
			SIZE sizeVpExt = { 0, 0 };
			if(!GetViewportExt(&sizeVpExt))
				return FALSE;
			lpSize->cx = ::MulDiv(lpSize->cx, abs(sizeVpExt.cx), abs(sizeWinExt.cx));
			lpSize->cy = ::MulDiv(lpSize->cy, abs(sizeVpExt.cy), abs(sizeWinExt.cy));
			return TRUE;
		}

		// Special Coordinate Functions (useful for dealing with metafiles and OLE)
#define HIMETRIC_INCH   2540    // HIMETRIC units per inch

		void DPtoHIMETRIC(LPSIZE lpSize) const
		{
			ASSERT(hdc_ != NULL);
			int nMapMode;
			if((nMapMode = GetMapMode()) < MM_ISOTROPIC && nMapMode != MM_TEXT)
			{
				// when using a constrained map mode, map against physical inch
				((DCHandle*)this)->SetMapMode(MM_HIMETRIC);
				DPtoLP(lpSize);
				((DCHandle*)this)->SetMapMode(nMapMode);
			}
			else
			{
				// map against logical inch for non-constrained mapping modes
				int cxPerInch = GetDeviceCaps(LOGPIXELSX);
				int cyPerInch = GetDeviceCaps(LOGPIXELSY);
				ASSERT(cxPerInch != 0 && cyPerInch != 0);
				lpSize->cx = ::MulDiv(lpSize->cx, HIMETRIC_INCH, cxPerInch);
				lpSize->cy = ::MulDiv(lpSize->cy, HIMETRIC_INCH, cyPerInch);
			}
		}

		void HIMETRICtoDP(LPSIZE lpSize) const
		{
			ASSERT(hdc_ != NULL);
			int nMapMode;
			if((nMapMode = GetMapMode()) < MM_ISOTROPIC && nMapMode != MM_TEXT)
			{
				// when using a constrained map mode, map against physical inch
				((DCHandle*)this)->SetMapMode(MM_HIMETRIC);
				LPtoDP(lpSize);
				((DCHandle*)this)->SetMapMode(nMapMode);
			}
			else
			{
				// map against logical inch for non-constrained mapping modes
				int cxPerInch = GetDeviceCaps(LOGPIXELSX);
				int cyPerInch = GetDeviceCaps(LOGPIXELSY);
				ASSERT(cxPerInch != 0 && cyPerInch != 0);
				lpSize->cx = ::MulDiv(lpSize->cx, cxPerInch, HIMETRIC_INCH);
				lpSize->cy = ::MulDiv(lpSize->cy, cyPerInch, HIMETRIC_INCH);
			}
		}

		void LPtoHIMETRIC(LPSIZE lpSize) const
		{
			LPtoDP(lpSize);
			DPtoHIMETRIC(lpSize);
		}

		void HIMETRICtoLP(LPSIZE lpSize) const
		{
			HIMETRICtoDP(lpSize);
			DPtoLP(lpSize);
		}
#endif // !_WIN32_WCE

		// Region Functions
		BOOL FillRgn(HRGN rgn, HBRUSH brush)
		{
			ASSERT(hdc_ != NULL);
			return ::FillRgn(hdc_, rgn, brush);
		}

#ifndef _WIN32_WCE
		BOOL FrameRgn(HRGN rgn, HBRUSH brush, int nWidth, int nHeight)
		{
			ASSERT(hdc_ != NULL);
			return ::FrameRgn(hdc_, rgn, brush, nWidth, nHeight);
		}

		BOOL InvertRgn(HRGN rgn)
		{
			ASSERT(hdc_ != NULL);
			return ::InvertRgn(hdc_, rgn);
		}

		BOOL PaintRgn(HRGN rgn)
		{
			ASSERT(hdc_ != NULL);
			return ::PaintRgn(hdc_, rgn);
		}
#endif // !_WIN32_WCE

		// Clipping Functions
		int GetClipBox(LPRECT lpRect) const
		{
			ASSERT(hdc_ != NULL);
			return ::GetClipBox(hdc_, lpRect);
		}

		int GetClipRgn(Rgn& region) const
		{
			ASSERT(hdc_ != NULL);
			if(region.IsNull())
				region.CreateRectRgn(0, 0, 0, 0);

			int nRet = ::GetClipRgn(hdc_, region);
			if(nRet != 1)
				region.DeleteObject();

			return nRet;
		}

#ifndef _WIN32_WCE
		BOOL PtVisible(int x, int y) const
		{
			ASSERT(hdc_ != NULL);
			return ::PtVisible(hdc_, x, y);
		}

		BOOL PtVisible(POINT point) const
		{
			ASSERT(hdc_ != NULL);
			return ::PtVisible(hdc_, point.x, point.y);
		}
#endif // !_WIN32_WCE

		BOOL RectVisible(LPCRECT lpRect) const
		{
			ASSERT(hdc_ != NULL);
			return ::RectVisible(hdc_, lpRect);
		}

		int SelectClipRgn(HRGN rgn)
		{
			ASSERT(hdc_ != NULL);
			return ::SelectClipRgn(hdc_, (HRGN)rgn);
		}

		int ExcludeClipRect(int x1, int y1, int x2, int y2)
		{
			ASSERT(hdc_ != NULL);
			return ::ExcludeClipRect(hdc_, x1, y1, x2, y2);
		}

		int ExcludeClipRect(LPCRECT lpRect)
		{
			ASSERT(hdc_ != NULL);
			return ::ExcludeClipRect(hdc_, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom);
		}

#ifndef _WIN32_WCE
		int ExcludeUpdateRgn(HWND hWnd)
		{
			ASSERT(hdc_ != NULL);
			return ::ExcludeUpdateRgn(hdc_, hWnd);
		}
#endif // !_WIN32_WCE

		int IntersectClipRect(int x1, int y1, int x2, int y2)
		{
			ASSERT(hdc_ != NULL);
			return ::IntersectClipRect(hdc_, x1, y1, x2, y2);
		}

		int IntersectClipRect(LPCRECT lpRect)
		{
			ASSERT(hdc_ != NULL);
			return ::IntersectClipRect(hdc_, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom);
		}

#ifndef _WIN32_WCE
		int OffsetClipRgn(int x, int y)
		{
			ASSERT(hdc_ != NULL);
			return ::OffsetClipRgn(hdc_, x, y);
		}

		int OffsetClipRgn(SIZE size)
		{
			ASSERT(hdc_ != NULL);
			return ::OffsetClipRgn(hdc_, size.cx, size.cy);
		}

		int SelectClipRgn(HRGN rgn, int nMode)
		{
			ASSERT(hdc_ != NULL);
			return ::ExtSelectClipRgn(hdc_, rgn, nMode);
		}
#endif // !_WIN32_WCE

		// Line-Output Functions
#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
		BOOL GetCurrentPosition(LPPOINT lpPoint) const
		{
			ASSERT(hdc_ != NULL);
			return ::GetCurrentPositionEx(hdc_, lpPoint);
		}

		BOOL MoveTo(int x, int y, LPPOINT lpPoint = NULL)
		{
			ASSERT(hdc_ != NULL);
			return ::MoveToEx(hdc_, x, y, lpPoint);
		}

		BOOL MoveTo(POINT point, LPPOINT lpPointRet = NULL)
		{
			ASSERT(hdc_ != NULL);
			return MoveTo(point.x, point.y, lpPointRet);
		}

		BOOL LineTo(int x, int y)
		{
			ASSERT(hdc_ != NULL);
			return ::LineTo(hdc_, x, y);
		}

		BOOL LineTo(POINT point)
		{
			ASSERT(hdc_ != NULL);
			return LineTo(point.x, point.y);
		}
#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)

#ifndef _WIN32_WCE
		BOOL Arc(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4)
		{
			ASSERT(hdc_ != NULL);
			return ::Arc(hdc_, x1, y1, x2, y2, x3, y3, x4, y4);
		}

		BOOL Arc(LPCRECT lpRect, POINT ptStart, POINT ptEnd)
		{
			ASSERT(hdc_ != NULL);
			return ::Arc(hdc_, lpRect->left, lpRect->top,
				lpRect->right, lpRect->bottom, ptStart.x, ptStart.y,
				ptEnd.x, ptEnd.y);
		}
#endif // !_WIN32_WCE

		BOOL Polyline(LPPOINT lpPoints, int nCount)
		{
			ASSERT(hdc_ != NULL);
			return ::Polyline(hdc_, lpPoints, nCount);
		}

#ifndef _WIN32_WCE
		BOOL AngleArc(int x, int y, int nRadius, float fStartAngle, float fSweepAngle)
		{
			ASSERT(hdc_ != NULL);
			return ::AngleArc(hdc_, x, y, nRadius, fStartAngle, fSweepAngle);
		}

		BOOL ArcTo(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4)
		{
			ASSERT(hdc_ != NULL);
			return ::ArcTo(hdc_, x1, y1, x2, y2, x3, y3, x4, y4);
		}

		BOOL ArcTo(LPCRECT lpRect, POINT ptStart, POINT ptEnd)
		{
			ASSERT(hdc_ != NULL);
			return ArcTo(lpRect->left, lpRect->top, lpRect->right,
				lpRect->bottom, ptStart.x, ptStart.y, ptEnd.x, ptEnd.y);
		}

		int GetArcDirection() const
		{
			ASSERT(hdc_ != NULL);
			return ::GetArcDirection(hdc_);
		}

		int SetArcDirection(int nArcDirection)
		{
			ASSERT(hdc_ != NULL);
			return ::SetArcDirection(hdc_, nArcDirection);
		}

		BOOL PolyDraw(const POINT* lpPoints, const BYTE* lpTypes, int nCount)
		{
			ASSERT(hdc_ != NULL);
			return ::PolyDraw(hdc_, lpPoints, lpTypes, nCount);
		}

		BOOL PolylineTo(const POINT* lpPoints, int nCount)
		{
			ASSERT(hdc_ != NULL);
			return ::PolylineTo(hdc_, lpPoints, nCount);
		}

		BOOL PolyPolyline(const POINT* lpPoints,
			const DWORD* lpPolyPoints, int nCount)
		{
			ASSERT(hdc_ != NULL);
			return ::PolyPolyline(hdc_, lpPoints, lpPolyPoints, nCount);
		}

		BOOL PolyBezier(const POINT* lpPoints, int nCount)
		{
			ASSERT(hdc_ != NULL);
			return ::PolyBezier(hdc_, lpPoints, nCount);
		}

		BOOL PolyBezierTo(const POINT* lpPoints, int nCount)
		{
			ASSERT(hdc_ != NULL);
			return ::PolyBezierTo(hdc_, lpPoints, nCount);
		}
#endif // !_WIN32_WCE

		// Simple Drawing Functions
		BOOL FillRect(LPCRECT lpRect, HBRUSH brush)
		{
			ASSERT(hdc_ != NULL);
			return ::FillRect(hdc_, lpRect, brush);
		}

		BOOL FillRect(LPCRECT lpRect, COLORREF color)
		{
			Brush b(color);
			return FillRect(lpRect, b);
		}

		BOOL FillRect(LPCRECT lpRect, int nColorIndex)
		{
			ASSERT(hdc_ != NULL);
#ifndef _WIN32_WCE
			return ::FillRect(hdc_, lpRect, (HBRUSH)LongToPtr(nColorIndex + 1));
#else // CE specific
			return ::FillRect(hdc_, lpRect, ::GetSysColorBrush(nColorIndex));
#endif // _WIN32_WCE
		}

#ifndef _WIN32_WCE
		BOOL FrameRect(LPCRECT lpRect, HBRUSH brush)
		{
			ASSERT(hdc_ != NULL);
			return ::FrameRect(hdc_, lpRect, brush);
		}
#endif // !_WIN32_WCE

#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 420)
		BOOL InvertRect(LPCRECT lpRect)
		{
			ASSERT(hdc_ != NULL);
			return ::InvertRect(hdc_, lpRect);
		}
#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 420)

		BOOL DrawIcon(int x, int y, HICON hIcon)
		{
			ASSERT(hdc_ != NULL);
#ifndef _WIN32_WCE
			return ::DrawIcon(hdc_, x, y, hIcon);
#else // CE specific
			return ::DrawIconEx(hdc_, x, y, hIcon, 0, 0, 0, NULL, DI_NORMAL);
#endif // _WIN32_WCE
		}

		BOOL DrawIcon(POINT point, HICON hIcon)
		{
			ASSERT(hdc_ != NULL);
#ifndef _WIN32_WCE
			return ::DrawIcon(hdc_, point.x, point.y, hIcon);
#else // CE specific
			return ::DrawIconEx(hdc_, point.x, point.y, hIcon, 0, 0, 0, NULL, DI_NORMAL);
#endif // _WIN32_WCE
		}

		BOOL DrawIconEx(int x, int y, HICON hIcon, int cxWidth, int cyWidth, UINT uStepIfAniCur = 0, HBRUSH hbrFlickerFreeDraw = NULL, UINT uFlags = DI_NORMAL)
		{
			ASSERT(hdc_ != NULL);
			return ::DrawIconEx(hdc_, x, y, hIcon, cxWidth, cyWidth, uStepIfAniCur, hbrFlickerFreeDraw, uFlags);
		}

		BOOL DrawIconEx(POINT point, HICON hIcon, SIZE size, UINT uStepIfAniCur = 0, HBRUSH hbrFlickerFreeDraw = NULL, UINT uFlags = DI_NORMAL)
		{
			ASSERT(hdc_ != NULL);
			return ::DrawIconEx(hdc_, point.x, point.y, hIcon, size.cx, size.cy, uStepIfAniCur, hbrFlickerFreeDraw, uFlags);
		}

#ifndef _WIN32_WCE
		BOOL DrawState(POINT pt, SIZE size, HBITMAP hBitmap, UINT nFlags, HBRUSH brush = NULL)
		{
			ASSERT(hdc_ != NULL);
			return ::DrawState(hdc_, brush, NULL, (LPARAM)hBitmap, 0, pt.x, pt.y, size.cx, size.cy, nFlags | DST_BITMAP);
		}

		BOOL DrawState(POINT pt, SIZE size, HICON hIcon, UINT nFlags, HBRUSH brush = NULL)
		{
			ASSERT(hdc_ != NULL);
			return ::DrawState(hdc_, brush, NULL, (LPARAM)hIcon, 0, pt.x, pt.y, size.cx, size.cy, nFlags | DST_ICON);
		}

		BOOL DrawState(POINT pt, SIZE size, LPCTSTR lpszText, UINT nFlags, BOOL bPrefixText = TRUE, int nTextLen = 0, HBRUSH brush = NULL)
		{
			ASSERT(hdc_ != NULL);
			return ::DrawState(hdc_, brush, NULL, (LPARAM)lpszText, (WPARAM)nTextLen, pt.x, pt.y, size.cx, size.cy, nFlags | (bPrefixText ? DST_PREFIXTEXT : DST_TEXT));
		}

		BOOL DrawState(POINT pt, SIZE size, DRAWSTATEPROC lpDrawProc, LPARAM lData, UINT nFlags, HBRUSH brush = NULL)
		{
			ASSERT(hdc_ != NULL);
			return ::DrawState(hdc_, brush, lpDrawProc, lData, 0, pt.x, pt.y, size.cx, size.cy, nFlags | DST_COMPLEX);
		}
#endif // !_WIN32_WCE

		// Ellipse and Polygon Functions
#ifndef _WIN32_WCE
		BOOL Chord(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4)
		{
			ASSERT(hdc_ != NULL);
			return ::Chord(hdc_, x1, y1, x2, y2, x3, y3, x4, y4);
		}

		BOOL Chord(LPCRECT lpRect, POINT ptStart, POINT ptEnd)
		{
			ASSERT(hdc_ != NULL);
			return ::Chord(hdc_, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, ptStart.x, ptStart.y, ptEnd.x, ptEnd.y);
		}
#endif // !_WIN32_WCE

		void DrawFocusRect(LPCRECT lpRect)
		{
			ASSERT(hdc_ != NULL);
			::DrawFocusRect(hdc_, lpRect);
		}

		BOOL Ellipse(int x1, int y1, int x2, int y2)
		{
			ASSERT(hdc_ != NULL);
			return ::Ellipse(hdc_, x1, y1, x2, y2);
		}

		BOOL Ellipse(LPCRECT lpRect)
		{
			ASSERT(hdc_ != NULL);
			return ::Ellipse(hdc_, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom);
		}

#ifndef _WIN32_WCE
		BOOL Pie(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4)
		{
			ASSERT(hdc_ != NULL);
			return ::Pie(hdc_, x1, y1, x2, y2, x3, y3, x4, y4);
		}

		BOOL Pie(LPCRECT lpRect, POINT ptStart, POINT ptEnd)
		{
			ASSERT(hdc_ != NULL);
			return ::Pie(hdc_, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, ptStart.x, ptStart.y, ptEnd.x, ptEnd.y);
		}
#endif // !_WIN32_WCE

		BOOL Polygon(LPPOINT lpPoints, int nCount)
		{
			ASSERT(hdc_ != NULL);
			return ::Polygon(hdc_, lpPoints, nCount);
		}

#ifndef _WIN32_WCE
		BOOL PolyPolygon(LPPOINT lpPoints, LPINT lpPolyCounts, int nCount)
		{
			ASSERT(hdc_ != NULL);
			return ::PolyPolygon(hdc_, lpPoints, lpPolyCounts, nCount);
		}
#endif // !_WIN32_WCE

		BOOL Rectangle(int x1, int y1, int x2, int y2)
		{
			ASSERT(hdc_ != NULL);
			return ::Rectangle(hdc_, x1, y1, x2, y2);
		}

		BOOL Rectangle(LPCRECT lpRect)
		{
			ASSERT(hdc_ != NULL);
			return ::Rectangle(hdc_, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom);
		}

		BOOL RoundRect(int x1, int y1, int x2, int y2, int x3, int y3)
		{
			ASSERT(hdc_ != NULL);
			return ::RoundRect(hdc_, x1, y1, x2, y2, x3, y3);
		}

		BOOL RoundRect(LPCRECT lpRect, POINT point)
		{
			ASSERT(hdc_ != NULL);
			return ::RoundRect(hdc_, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, point.x, point.y);
		}

		// Bitmap Functions
		BOOL PatBlt(int x, int y, int nWidth, int nHeight, DWORD dwRop)
		{
			ASSERT(hdc_ != NULL);
			return ::PatBlt(hdc_, x, y, nWidth, nHeight, dwRop);
		}

		BOOL BitBlt(int x, int y, int nWidth, int nHeight, HDC hSrcDC,
			int xSrc, int ySrc, DWORD dwRop)
		{
			ASSERT(hdc_ != NULL);
			return ::BitBlt(hdc_, x, y, nWidth, nHeight, hSrcDC, xSrc, ySrc, dwRop);
		}

		BOOL StretchBlt(int x, int y, int nWidth, int nHeight, HDC hSrcDC, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, DWORD dwRop)
		{
			ASSERT(hdc_ != NULL);
			return ::StretchBlt(hdc_, x, y, nWidth, nHeight, hSrcDC, xSrc, ySrc, nSrcWidth, nSrcHeight, dwRop);
		}

		COLORREF GetPixel(int x, int y) const
		{
			ASSERT(hdc_ != NULL);
			return ::GetPixel(hdc_, x, y);
		}

		COLORREF GetPixel(POINT point) const
		{
			ASSERT(hdc_ != NULL);
			return ::GetPixel(hdc_, point.x, point.y);
		}

		COLORREF SetPixel(int x, int y, COLORREF crColor)
		{
			ASSERT(hdc_ != NULL);
			return ::SetPixel(hdc_, x, y, crColor);
		}

		COLORREF SetPixel(POINT point, COLORREF crColor)
		{
			ASSERT(hdc_ != NULL);
			return ::SetPixel(hdc_, point.x, point.y, crColor);
		}

#ifndef _WIN32_WCE
		BOOL FloodFill(int x, int y, COLORREF crColor)
		{
			ASSERT(hdc_ != NULL);
			return ::FloodFill(hdc_, x, y, crColor);
		}

		BOOL ExtFloodFill(int x, int y, COLORREF crColor, UINT nFillType)
		{
			ASSERT(hdc_ != NULL);
			return ::ExtFloodFill(hdc_, x, y, crColor, nFillType);
		}
#endif // !_WIN32_WCE

		BOOL MaskBlt(int x, int y, int nWidth, int nHeight, HDC hSrcDC, int xSrc, int ySrc, HBITMAP hMaskBitmap, int xMask, int yMask, DWORD dwRop)
		{
			ASSERT(hdc_ != NULL);
			return ::MaskBlt(hdc_, x, y, nWidth, nHeight, hSrcDC, xSrc, ySrc, hMaskBitmap, xMask, yMask, dwRop);
		}

#ifndef _WIN32_WCE
		BOOL PlgBlt(LPPOINT lpPoint, HDC hSrcDC, int xSrc, int ySrc, int nWidth, int nHeight, HBITMAP hMaskBitmap, int xMask, int yMask)
		{
			ASSERT(hdc_ != NULL);
			return ::PlgBlt(hdc_, lpPoint, hSrcDC, xSrc, ySrc, nWidth, nHeight, hMaskBitmap, xMask, yMask);
		}

		BOOL SetPixelV(int x, int y, COLORREF crColor)
		{
			ASSERT(hdc_ != NULL);
			return ::SetPixelV(hdc_, x, y, crColor);
		}

		BOOL SetPixelV(POINT point, COLORREF crColor)
		{
			ASSERT(hdc_ != NULL);
			return ::SetPixelV(hdc_, point.x, point.y, crColor);
		}
#endif // !_WIN32_WCE

#if !defined(_ATL_NO_MSIMG) || defined(_WIN32_WCE)
#ifndef _WIN32_WCE
		BOOL TransparentBlt(int x, int y, int nWidth, int nHeight, HDC hSrcDC, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, UINT crTransparent)
		{
			ASSERT(hdc_ != NULL);
			return ::TransparentBlt(hdc_, x, y, nWidth, nHeight, hSrcDC, xSrc, ySrc, nSrcWidth, nSrcHeight, crTransparent);
		}
#else // CE specific
		BOOL TransparentImage(int x, int y, int nWidth, int nHeight, HDC hSrcDC, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, UINT crTransparent)
		{
			ASSERT(hdc_ != NULL);
			return ::TransparentImage(hdc_, x, y, nWidth, nHeight, hSrcDC, xSrc, ySrc, nSrcWidth, nSrcHeight, crTransparent);
		}
#endif // _WIN32_WCE

#if (!defined(_WIN32_WCE) || (_WIN32_WCE >= 420))
		BOOL GradientFill(const PTRIVERTEX pVertices, DWORD nVertices, void* pMeshElements, DWORD nMeshElements, DWORD dwMode)
		{
			ASSERT(hdc_ != NULL);
			return ::GradientFill(hdc_, pVertices, nVertices, pMeshElements, nMeshElements, dwMode);
		}

		BOOL GradientFillRect(RECT& rect, COLORREF clr1, COLORREF clr2, bool bHorizontal)
		{
			ASSERT(hdc_ != NULL);

			TRIVERTEX arrTvx[2] = { { 0 }, { 0 } };

			arrTvx[0].x = rect.left;
			arrTvx[0].y = rect.top;
			arrTvx[0].Red = MAKEWORD(0, GetRValue(clr1));
			arrTvx[0].Green = MAKEWORD(0, GetGValue(clr1));
			arrTvx[0].Blue = MAKEWORD(0, GetBValue(clr1));
			arrTvx[0].Alpha = 0;

			arrTvx[1].x = rect.right;
			arrTvx[1].y = rect.bottom;
			arrTvx[1].Red = MAKEWORD(0, GetRValue(clr2));
			arrTvx[1].Green = MAKEWORD(0, GetGValue(clr2));
			arrTvx[1].Blue = MAKEWORD(0, GetBValue(clr2));
			arrTvx[1].Alpha = 0;

			GRADIENT_RECT gr = { 0, 1 };

			return ::GradientFill(hdc_, arrTvx, 2, &gr, 1, bHorizontal ? GRADIENT_FILL_RECT_H : GRADIENT_FILL_RECT_V);
		}
#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 420)

#if !defined(_WIN32_WCE) || (_WIN32_WCE > 0x500)
		BOOL AlphaBlend(int x, int y, int nWidth, int nHeight, HDC hSrcDC, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, BLENDFUNCTION bf)
		{
			ASSERT(hdc_ != NULL);
			return ::AlphaBlend(hdc_, x, y, nWidth, nHeight, hSrcDC, xSrc, ySrc, nSrcWidth, nSrcHeight, bf);
		}
#endif // !defined(_WIN32_WCE) || (_WIN32_WCE > 0x500)
#endif //  !defined(_ATL_NO_MSIMG) || defined(_WIN32_WCE)

		// Extra bitmap functions
		// Helper function for painting a disabled toolbar or menu bitmap
		// This function can take either an HBITMAP (for SS) or a DC with 
		//           the bitmap already painted (for cmdbar)
		BOOL DitherBlt(int x, int y, int nWidth, int nHeight, HDC hSrcDC, HBITMAP hBitmap, int xSrc, int ySrc,
			HBRUSH brushBackground = ::GetSysColorBrush(COLOR_3DFACE),
			HBRUSH brush3DEffect = ::GetSysColorBrush(COLOR_3DHILIGHT),
			HBRUSH brushDisabledImage = ::GetSysColorBrush(COLOR_3DSHADOW))
		{
			ASSERT(hdc_ != NULL || hBitmap != NULL);
			ASSERT(nWidth > 0 && nHeight > 0);

			// Create a generic DC for all BitBlts
			DCHandle dc = (hSrcDC != NULL) ? hSrcDC : ::CreateCompatibleDC(hdc_);
			ASSERT(dc.hdc_ != NULL);
			if(dc.hdc_ == NULL)
				return FALSE;

			// Create a DC for the monochrome DIB section
			DC dcBW = ::CreateCompatibleDC(hdc_);
			ASSERT(dcBW.hdc_ != NULL);
			if(dcBW.hdc_ == NULL)
			{
				if(hSrcDC == NULL)
					dc.DeleteDC();
				return FALSE;
			}

			// Create the monochrome DIB section with a black and white palette
			struct RGBBWBITMAPINFO
			{
				BITMAPINFOHEADER bmiHeader; 
				RGBQUAD bmiColors[2]; 
			};

			RGBBWBITMAPINFO rgbBWBitmapInfo = 
			{
				{ sizeof(BITMAPINFOHEADER), nWidth, nHeight, 1, 1, BI_RGB, 0, 0, 0, 0, 0 },
				{ { 0x00, 0x00, 0x00, 0x00 }, { 0xFF, 0xFF, 0xFF, 0x00 } }
			};

			VOID* pbitsBW;
			Bitmap bmpBW = ::CreateDIBSection(dcBW, (LPBITMAPINFO)&rgbBWBitmapInfo, DIB_RGB_COLORS, &pbitsBW, NULL, 0);
			ASSERT(bmpBW.bitmap_ != NULL);
			if(bmpBW.bitmap_ == NULL)
			{
				if(hSrcDC == NULL)
					dc.DeleteDC();
				return FALSE;
			}

			// Attach the monochrome DIB section and the bitmap to the DCs
			HBITMAP hbmOldBW = dcBW.SelectBitmap(bmpBW);
			HBITMAP hbmOldDC = NULL;
			if(hBitmap != NULL)
				hbmOldDC = dc.SelectBitmap(hBitmap);

			// Block: Dark gray removal: we want (128, 128, 128) pixels to become black and not white
			{
				DC dcTemp1 = ::CreateCompatibleDC(hdc_);
				DC dcTemp2 = ::CreateCompatibleDC(hdc_);
				Bitmap bmpTemp1;
				bmpTemp1.CreateCompatibleBitmap(dc, nWidth, nHeight);
				Bitmap bmpTemp2;
				bmpTemp2.CreateBitmap(nWidth, nHeight, 1, 1, NULL);
				HBITMAP hOldBmp1 = dcTemp1.SelectBitmap(bmpTemp1);
				HBITMAP hOldBmp2 = dcTemp2.SelectBitmap(bmpTemp2);
				// Let's copy our image, it will be altered
				dcTemp1.BitBlt(0, 0, nWidth, nHeight, dc, xSrc, ySrc, SRCCOPY);

				// All dark gray pixels will become white, the others black
				dcTemp1.SetBkColor(RGB(128, 128, 128));
				dcTemp2.BitBlt(0, 0, nWidth, nHeight, dcTemp1, 0, 0, SRCCOPY);
				// Do an XOR to set to black these white pixels
				dcTemp1.BitBlt(0, 0, nWidth, nHeight, dcTemp2, 0, 0, SRCINVERT);

				// BitBlt the bitmap into the monochrome DIB section
				// The DIB section will do a true monochrome conversion
				// The magenta background being closer to white will become white
				dcBW.BitBlt(0, 0, nWidth, nHeight, dcTemp1, 0, 0, SRCCOPY);

				// Cleanup
				dcTemp1.SelectBitmap(hOldBmp1);
				dcTemp2.SelectBitmap(hOldBmp2);
			}

			// Paint the destination rectangle using brushBackground
			if(brushBackground != NULL)
			{
				RECT rc = { x, y, x + nWidth, y + nHeight };
				FillRect(&rc, brushBackground);
			}

			// BitBlt the black bits in the monochrome bitmap into brush3DEffect color in the destination DC
			// The magic ROP comes from the Charles Petzold's book
			HBRUSH hOldBrush = SelectBrush(brush3DEffect);
			BitBlt(x + 1, y + 1, nWidth, nHeight, dcBW, 0, 0, 0xB8074A);

			// BitBlt the black bits in the monochrome bitmap into brushDisabledImage color in the destination DC
			SelectBrush(brushDisabledImage);
			BitBlt(x, y, nWidth, nHeight, dcBW, 0, 0, 0xB8074A);

			SelectBrush(hOldBrush);
			dcBW.SelectBitmap(hbmOldBW);
			dc.SelectBitmap(hbmOldDC);

			if(hSrcDC == NULL)
				dc.DeleteDC();

			return TRUE;
		}

		// Text Functions
#ifndef _WIN32_WCE
		BOOL TextOut(int x, int y, LPCTSTR lpszString, int nCount = -1)
		{
			ASSERT(hdc_ != NULL);
			if(nCount == -1)
				nCount = lstrlen(lpszString);
			return ::TextOut(hdc_, x, y, lpszString, nCount);
		}
#endif // !_WIN32_WCE

		BOOL ExtTextOut(int x, int y, UINT nOptions, LPCRECT lpRect, LPCTSTR lpszString, UINT nCount = -1, LPINT lpDxWidths = NULL)
		{
			ASSERT(hdc_ != NULL);
			if(nCount == -1)
				nCount = lstrlen(lpszString);
			return ::ExtTextOut(hdc_, x, y, nOptions, lpRect, lpszString, nCount, lpDxWidths);
		}

#ifndef _WIN32_WCE
		SIZE TabbedTextOut(int x, int y, LPCTSTR lpszString, int nCount = -1, int nTabPositions = 0, LPINT lpnTabStopPositions = NULL, int nTabOrigin = 0)
		{
			ASSERT(hdc_ != NULL);
			if(nCount == -1)
				nCount = lstrlen(lpszString);
			LONG lRes = ::TabbedTextOut(hdc_, x, y, lpszString, nCount, nTabPositions, lpnTabStopPositions, nTabOrigin);
			SIZE size = { GET_X_LPARAM(lRes), GET_Y_LPARAM(lRes) };
			return size;
		}
#endif // !_WIN32_WCE

		int DrawText(LPCTSTR lpstrText, int cchText, LPRECT lpRect, UINT uFormat)
		{
			ASSERT(hdc_ != NULL);
#ifndef _WIN32_WCE
			ASSERT((uFormat & DT_MODIFYSTRING) == 0);
#endif // !_WIN32_WCE
			return ::DrawText(hdc_, lpstrText, cchText, lpRect, uFormat);
		}

		int DrawText(LPTSTR lpstrText, int cchText, LPRECT lpRect, UINT uFormat)
		{
			ASSERT(hdc_ != NULL);
			return ::DrawText(hdc_, lpstrText, cchText, lpRect, uFormat);
		}

		int DrawText(LPCTSTR lpstrText, LPRECT lpRect, UINT uFormat, HFONT font, COLORREF color, BOOL transparent)
		{
			HFONT oldfont = SelectFont(font);
			COLORREF oldcolor = SetTextColor(color);
			int bkmode;
			bkmode = SetBkMode(transparent ? TRANSPARENT : OPAQUE);
			int ret = DrawText(lpstrText, _tcslen(lpstrText), lpRect, uFormat);
			SelectFont(oldfont);
			SetTextColor(oldcolor);
			SetBkMode(bkmode);
			return ret;
		}

#ifndef _WIN32_WCE
		int DrawTextEx(LPTSTR lpstrText, int cchText, LPRECT lpRect, UINT uFormat, LPDRAWTEXTPARAMS lpDTParams = NULL)
		{
			ASSERT(hdc_ != NULL);
			return ::DrawTextEx(hdc_, lpstrText, cchText, lpRect, uFormat, lpDTParams);
		}
#endif // !_WIN32_WCE

#if (_WIN32_WINNT >= 0x0501)
		int DrawShadowText(LPCWSTR lpstrText, int cchText, LPRECT lpRect, DWORD dwFlags, COLORREF clrText, COLORREF clrShadow, int xOffset, int yOffset)
		{
			ASSERT(hdc_ != NULL);
			// This function is present only if comctl32.dll version 6 is loaded;
			// we use LoadLibrary/GetProcAddress to allow apps compiled with
			// _WIN32_WINNT >= 0x0501 to run on older Windows/CommCtrl
			int nRet = 0;
			HMODULE hCommCtrlDLL = ::LoadLibrary(_T("comctl32.dll"));
			ASSERT(hCommCtrlDLL != NULL);
			if(hCommCtrlDLL != NULL)
			{
				typedef int (WINAPI *PFN_DrawShadowText)(HDC dc, LPCWSTR lpstrText, UINT cchText, LPRECT lpRect, DWORD dwFlags, COLORREF clrText, COLORREF clrShadow, int xOffset, int yOffset);
				PFN_DrawShadowText pfnDrawShadowText = (PFN_DrawShadowText)::GetProcAddress(hCommCtrlDLL, "DrawShadowText");
				ASSERT(pfnDrawShadowText != NULL);   // this function requires CommCtrl6
				if(pfnDrawShadowText != NULL)
					nRet = pfnDrawShadowText(hdc_, lpstrText, cchText, lpRect, dwFlags, clrText, clrShadow, xOffset, yOffset);
				::FreeLibrary(hCommCtrlDLL);
			}
			return nRet;
		}
#endif // (_WIN32_WINNT >= 0x0501)

// 		void DrawHtml(LPCTSTR lpszText, Rect& rc, UINT uFormat)
// 		{
// 			ASSERT(hdc_ != NULL);
// 			if (lpszText == NULL || rc.isempty()) return;
// 			
// 			bool bdraw = (uFormat | DT_CALCRECT) == 0;
// 
// 			Rect rclip;
// 			GetClientRect(&rclip);
// 			HRGN hOldRgn = ::CreateRectRgnIndirect(&rclip);
// 			HRGN hrgn = ::CreateRectRgnIndirect(&rc);
// 			if (bdraw)
// 				::ExtSelectClipRgn(hdc_, hrgn, RGN_AND);
// 
// 		}

		BOOL GetTextExtent(LPCTSTR lpszString, int nCount, LPSIZE lpSize) const
		{
			ASSERT(hdc_ != NULL);
			if(nCount == -1)
				nCount = lstrlen(lpszString);
			return ::GetTextExtentPoint32(hdc_, lpszString, nCount, lpSize);
		}

		BOOL GetTextExtentExPoint(LPCTSTR lpszString, int cchString, LPSIZE lpSize, int nMaxExtent, LPINT lpnFit = NULL, LPINT alpDx = NULL)
		{
			ASSERT(hdc_ != NULL);
			return ::GetTextExtentExPoint(hdc_, lpszString, cchString, nMaxExtent, lpnFit, alpDx, lpSize);
		}

#ifndef _WIN32_WCE
		DWORD GetTabbedTextExtent(LPCTSTR lpszString, int nCount = -1, int nTabPositions = 0, LPINT lpnTabStopPositions = NULL) const
		{
			ASSERT(hdc_ != NULL);
			if(nCount == -1)
				nCount = lstrlen(lpszString);
			return ::GetTabbedTextExtent(hdc_, lpszString, nCount, nTabPositions, lpnTabStopPositions);
		}

		BOOL GrayString(HBRUSH brush, BOOL (CALLBACK* lpfnOutput)(HDC, LPARAM, int), LPARAM lpData, int nCount, int x, int y, int nWidth, int nHeight)
		{
			ASSERT(hdc_ != NULL);
			return ::GrayString(hdc_, brush, (GRAYSTRINGPROC)lpfnOutput, lpData, nCount, x, y, nWidth, nHeight);
		}
#endif // !_WIN32_WCE

#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
		UINT GetTextAlign() const
		{
			ASSERT(hdc_ != NULL);
			return ::GetTextAlign(hdc_);
		}

		UINT SetTextAlign(UINT nFlags)
		{
			ASSERT(hdc_ != NULL);
			return ::SetTextAlign(hdc_, nFlags);
		}
#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)

		int GetTextFace(LPTSTR lpszFacename, int nCount) const
		{
			ASSERT(hdc_ != NULL);
			return ::GetTextFace(hdc_, nCount, lpszFacename);
		}

		int GetTextFaceLen() const
		{
			ASSERT(hdc_ != NULL);
			return ::GetTextFace(hdc_, 0, NULL);
		}

#ifndef _ATL_NO_COM
#ifdef _OLEAUTO_H_
		BOOL GetTextFace(BSTR& bstrFace) const
		{
			USES_CONVERSION;
			ASSERT(hdc_ != NULL);
			ASSERT(bstrFace == NULL);

			int nLen = GetTextFaceLen();
			if(nLen == 0)
				return FALSE;

			CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;
			LPTSTR lpszText = buff.Allocate(nLen);
			if(lpszText == NULL)
				return FALSE;

			if(!GetTextFace(lpszText, nLen))
				return FALSE;

			bstrFace = ::SysAllocString(T2OLE(lpszText));
			return (bstrFace != NULL) ? TRUE : FALSE;
		}
#endif
#endif // !_ATL_NO_COM

#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
		int GetTextFace(_CSTRING_NS::CString& strFace) const
		{
			ASSERT(hdc_ != NULL);

			int nLen = GetTextFaceLen();
			if(nLen == 0)
				return 0;

			LPTSTR lpstr = strFace.GetBufferSetLength(nLen);
			if(lpstr == NULL)
				return 0;
			int nRet = GetTextFace(lpstr, nLen);
			strFace.ReleaseBuffer();
			return nRet;
		}
#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)

		BOOL GetTextMetrics(LPTEXTMETRIC lpMetrics) const
		{
			ASSERT(hdc_ != NULL);
			return ::GetTextMetrics(hdc_, lpMetrics);
		}

#ifndef _WIN32_WCE
		int SetTextJustification(int nBreakExtra, int nBreakCount)
		{
			ASSERT(hdc_ != NULL);
			return ::SetTextJustification(hdc_, nBreakExtra, nBreakCount);
		}

		int GetTextCharacterExtra() const
		{
			ASSERT(hdc_ != NULL);
			return ::GetTextCharacterExtra(hdc_);
		}

		int SetTextCharacterExtra(int nCharExtra)
		{
			ASSERT(hdc_ != NULL);
			return ::SetTextCharacterExtra(hdc_, nCharExtra);
		}
#endif // !_WIN32_WCE

		// Advanced Drawing
		BOOL DrawEdge(LPRECT lpRect, UINT nEdge, UINT nFlags)
		{
			ASSERT(hdc_ != NULL);
			return ::DrawEdge(hdc_, lpRect, nEdge, nFlags);
		}

		BOOL DrawFrameControl(LPRECT lpRect, UINT nType, UINT nState)
		{
			ASSERT(hdc_ != NULL);
			return ::DrawFrameControl(hdc_, lpRect, nType, nState);
		}

		// Scrolling Functions
		BOOL ScrollDC(int dx, int dy, LPCRECT lpRectScroll, LPCRECT lpRectClip, HRGN rgnUpdate, LPRECT lpRectUpdate)
		{
			ASSERT(hdc_ != NULL);
			return ::ScrollDC(hdc_, dx, dy, lpRectScroll, lpRectClip, rgnUpdate, lpRectUpdate);
		}

		// Font Functions
#ifndef _WIN32_WCE
		BOOL GetCharWidth(UINT nFirstChar, UINT nLastChar, LPINT lpBuffer) const
		{
			ASSERT(hdc_ != NULL);
			return ::GetCharWidth(hdc_, nFirstChar, nLastChar, lpBuffer);
		}

		// GetCharWidth32 is not supported under Win9x
		BOOL GetCharWidth32(UINT nFirstChar, UINT nLastChar, LPINT lpBuffer) const
		{
			ASSERT(hdc_ != NULL);
			return ::GetCharWidth32(hdc_, nFirstChar, nLastChar, lpBuffer);
		}

		DWORD SetMapperFlags(DWORD dwFlag)
		{
			ASSERT(hdc_ != NULL);
			return ::SetMapperFlags(hdc_, dwFlag);
		}

		BOOL GetAspectRatioFilter(LPSIZE lpSize) const
		{
			ASSERT(hdc_ != NULL);
			return ::GetAspectRatioFilterEx(hdc_, lpSize);
		}

		BOOL GetCharABCWidths(UINT nFirstChar, UINT nLastChar, LPABC lpabc) const
		{
			ASSERT(hdc_ != NULL);
			return ::GetCharABCWidths(hdc_, nFirstChar, nLastChar, lpabc);
		}

		DWORD GetFontData(DWORD dwTable, DWORD dwOffset, LPVOID lpData, DWORD cbData) const
		{
			ASSERT(hdc_ != NULL);
			return ::GetFontData(hdc_, dwTable, dwOffset, lpData, cbData);
		}

		int GetKerningPairs(int nPairs, LPKERNINGPAIR lpkrnpair) const
		{
			ASSERT(hdc_ != NULL);
			return ::GetKerningPairs(hdc_, nPairs, lpkrnpair);
		}

		UINT GetOutlineTextMetrics(UINT cbData, LPOUTLINETEXTMETRIC lpotm) const
		{
			ASSERT(hdc_ != NULL);
			return ::GetOutlineTextMetrics(hdc_, cbData, lpotm);
		}

		DWORD GetGlyphOutline(UINT nChar, UINT nFormat, LPGLYPHMETRICS lpgm, DWORD cbBuffer, LPVOID lpBuffer, const MAT2* lpmat2) const
		{
			ASSERT(hdc_ != NULL);
			return ::GetGlyphOutline(hdc_, nChar, nFormat, lpgm, cbBuffer, lpBuffer, lpmat2);
		}

		BOOL GetCharABCWidths(UINT nFirstChar, UINT nLastChar, LPABCFLOAT lpABCF) const
		{
			ASSERT(hdc_ != NULL);
			return ::GetCharABCWidthsFloat(hdc_, nFirstChar, nLastChar, lpABCF);
		}

		BOOL GetCharWidth(UINT nFirstChar, UINT nLastChar, float* lpFloatBuffer) const
		{
			ASSERT(hdc_ != NULL);
			return ::GetCharWidthFloat(hdc_, nFirstChar, nLastChar, lpFloatBuffer);
		}
#endif // !_WIN32_WCE

		// Printer/Device Escape Functions
#ifndef _WIN32_WCE
		int Escape(int nEscape, int nCount, LPCSTR lpszInData, LPVOID lpOutData)
		{
			ASSERT(hdc_ != NULL);
			return ::Escape(hdc_, nEscape, nCount, lpszInData, lpOutData);
		}
#endif // !_WIN32_WCE

		int Escape(int nEscape, int nInputSize, LPCSTR lpszInputData,
			int nOutputSize, LPSTR lpszOutputData)
		{
			ASSERT(hdc_ != NULL);
			return ::ExtEscape(hdc_, nEscape, nInputSize, lpszInputData, nOutputSize, lpszOutputData);
		}

#ifndef _WIN32_WCE
		int DrawEscape(int nEscape, int nInputSize, LPCSTR lpszInputData)
		{
			ASSERT(hdc_ != NULL);
			return ::DrawEscape(hdc_, nEscape, nInputSize, lpszInputData);
		}
#endif // !_WIN32_WCE

		// Escape helpers
#if !defined(_WIN32_WCE) || ((_WIN32_WCE >= 200) && defined(StartDoc))
		int StartDoc(LPCTSTR lpszDocName)  // old Win3.0 version
		{
			DOCINFO di = { 0 };
			di.cbSize = sizeof(DOCINFO);
			di.lpszDocName = lpszDocName;
			return StartDoc(&di);
		}

		int StartDoc(LPDOCINFO lpDocInfo)
		{
			ASSERT(hdc_ != NULL);
			return ::StartDoc(hdc_, lpDocInfo);
		}

		int StartPage()
		{
			ASSERT(hdc_ != NULL);
			return ::StartPage(hdc_);
		}

		int EndPage()
		{
			ASSERT(hdc_ != NULL);
			return ::EndPage(hdc_);
		}

		int SetAbortProc(BOOL (CALLBACK* lpfn)(HDC, int))
		{
			ASSERT(hdc_ != NULL);
			return ::SetAbortProc(hdc_, (ABORTPROC)lpfn);
		}

		int AbortDoc()
		{
			ASSERT(hdc_ != NULL);
			return ::AbortDoc(hdc_);
		}

		int EndDoc()
		{
			ASSERT(hdc_ != NULL);
			return ::EndDoc(hdc_);
		}
#endif // !defined(_WIN32_WCE) || ((_WIN32_WCE >= 200) && defined(StartDoc))

		// MetaFile Functions
#ifndef _WIN32_WCE
		BOOL PlayMetaFile(HMETAFILE hMF)
		{
			ASSERT(hdc_ != NULL);
			if(::GetDeviceCaps(hdc_, TECHNOLOGY) == DT_METAFILE)
			{
				// playing metafile in metafile, just use core windows API
				return ::PlayMetaFile(hdc_, hMF);
			}

			// for special playback, lParam == pDC
			return ::EnumMetaFile(hdc_, hMF, EnumMetaFileProc, (LPARAM)this);
		}

		BOOL PlayMetaFile(HENHMETAFILE hEnhMetaFile, LPCRECT lpBounds)
		{
			ASSERT(hdc_ != NULL);
			return ::PlayEnhMetaFile(hdc_, hEnhMetaFile, lpBounds);
		}

		BOOL AddMetaFileComment(UINT nDataSize, const BYTE* pCommentData) // can be used for enhanced metafiles only
		{
			ASSERT(hdc_ != NULL);
			return ::GdiComment(hdc_, nDataSize, pCommentData);
		}

		// Special handling for metafile playback
		static int CALLBACK EnumMetaFileProc(HDC dc, HANDLETABLE* pHandleTable, METARECORD* pMetaRec, int nHandles, LPARAM lParam)
		{
			DCHandle* pDC = (DCHandle*)lParam;

			switch (pMetaRec->rdFunction)
			{
			case META_SETMAPMODE:
				pDC->SetMapMode((int)(short)pMetaRec->rdParm[0]);
				break;
			case META_SETWINDOWEXT:
				pDC->SetWindowExt((int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]);
				break;
			case META_SETWINDOWORG:
				pDC->SetWindowOrg((int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]);
				break;
			case META_SETVIEWPORTEXT:
				pDC->SetViewportExt((int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]);
				break;
			case META_SETVIEWPORTORG:
				pDC->SetViewportOrg((int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]);
				break;
			case META_SCALEWINDOWEXT:
				pDC->ScaleWindowExt((int)(short)pMetaRec->rdParm[3], (int)(short)pMetaRec->rdParm[2], 
					(int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]);
				break;
			case META_SCALEVIEWPORTEXT:
				pDC->ScaleViewportExt((int)(short)pMetaRec->rdParm[3], (int)(short)pMetaRec->rdParm[2],
					(int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]);
				break;
			case META_OFFSETVIEWPORTORG:
				pDC->OffsetViewportOrg((int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]);
				break;
			case META_SAVEDC:
				pDC->SaveDC();
				break;
			case META_RESTOREDC:
				pDC->RestoreDC((int)(short)pMetaRec->rdParm[0]);
				break;
			case META_SETBKCOLOR:
				pDC->SetBkColor(*(UNALIGNED COLORREF*)&pMetaRec->rdParm[0]);
				break;
			case META_SETTEXTCOLOR:
				pDC->SetTextColor(*(UNALIGNED COLORREF*)&pMetaRec->rdParm[0]);
				break;

				// need to watch out for SelectObject(HFONT), for custom font mapping
			case META_SELECTOBJECT:
				{
					HGDIOBJ hObject = pHandleTable->objectHandle[pMetaRec->rdParm[0]];
					UINT nObjType = ::GetObjectType(hObject);
					if(nObjType == 0)
					{
						// object type is unknown, determine if it is a font
						HFONT hStockFont = (HFONT)::GetStockObject(SYSTEM_FONT);
						HFONT hFontOld = (HFONT)::SelectObject(pDC->hdc_, hStockFont);
						HGDIOBJ hObjOld = ::SelectObject(pDC->hdc_, hObject);
						if(hObjOld == hStockFont)
						{
							// got the stock object back, so must be selecting a font
							pDC->SelectFont((HFONT)hObject);
							break;  // don't play the default record
						}
						else
						{
							// didn't get the stock object back, so restore everything
							::SelectObject(pDC->hdc_, hFontOld);
							::SelectObject(pDC->hdc_, hObjOld);
						}
						// and fall through to PlayMetaFileRecord...
					}
					else if(nObjType == OBJ_FONT)
					{
						// play back as CDCHandle::SelectFont(HFONT)
						pDC->SelectFont((HFONT)hObject);
						break;  // don't play the default record
					}
				}
				// fall through...

			default:
				::PlayMetaFileRecord(dc, pHandleTable, pMetaRec, nHandles);
				break;
			}

			return 1;
		}
#endif // !_WIN32_WCE

		// Path Functions
#ifndef _WIN32_WCE
		BOOL AbortPath()
		{
			ASSERT(hdc_ != NULL);
			return ::AbortPath(hdc_);
		}

		BOOL BeginPath()
		{
			ASSERT(hdc_ != NULL);
			return ::BeginPath(hdc_);
		}

		BOOL CloseFigure()
		{
			ASSERT(hdc_ != NULL);
			return ::CloseFigure(hdc_);
		}

		BOOL EndPath()
		{
			ASSERT(hdc_ != NULL);
			return ::EndPath(hdc_);
		}

		BOOL FillPath()
		{
			ASSERT(hdc_ != NULL);
			return ::FillPath(hdc_);
		}

		BOOL FlattenPath()
		{
			ASSERT(hdc_ != NULL);
			return ::FlattenPath(hdc_);
		}

		BOOL StrokeAndFillPath()
		{
			ASSERT(hdc_ != NULL);
			return ::StrokeAndFillPath(hdc_);
		}

		BOOL StrokePath()
		{
			ASSERT(hdc_ != NULL);
			return ::StrokePath(hdc_);
		}

		BOOL WidenPath()
		{
			ASSERT(hdc_ != NULL);
			return ::WidenPath(hdc_);
		}

		BOOL GetMiterLimit(PFLOAT pfMiterLimit) const
		{
			ASSERT(hdc_ != NULL);
			return ::GetMiterLimit(hdc_, pfMiterLimit);
		}

		BOOL SetMiterLimit(float fMiterLimit)
		{
			ASSERT(hdc_ != NULL);
			return ::SetMiterLimit(hdc_, fMiterLimit, NULL);
		}

		int GetPath(LPPOINT lpPoints, LPBYTE lpTypes, int nCount) const
		{
			ASSERT(hdc_ != NULL);
			return ::GetPath(hdc_, lpPoints, lpTypes, nCount);
		}

		BOOL SelectClipPath(int nMode)
		{
			ASSERT(hdc_ != NULL);
			return ::SelectClipPath(hdc_, nMode);
		}
#endif // !_WIN32_WCE

		// Misc Helper Functions
		static BrushHandle PASCAL GetHalftoneBrush()
		{
			HBRUSH halftoneBrush = NULL;
			WORD grayPattern[8] = { 0 };
			for(int i = 0; i < 8; i++)
				grayPattern[i] = (WORD)(0x5555 << (i & 1));
			HBITMAP grayBitmap = CreateBitmap(8, 8, 1, 1, &grayPattern);
			if(grayBitmap != NULL)
			{
				halftoneBrush = ::CreatePatternBrush(grayBitmap);
				DeleteObject(grayBitmap);
			}
			return BrushHandle(halftoneBrush);
		}

		void DrawDragRect(LPCRECT lpRect, SIZE size, LPCRECT lpRectLast, SIZE sizeLast, HBRUSH brush = NULL, HBRUSH brushLast = NULL)
		{
			// first, determine the update region and select it
			Rgn rgnOutside;
			rgnOutside.CreateRectRgnIndirect(lpRect);
			RECT rect = *lpRect;
			::InflateRect(&rect, -size.cx, -size.cy);
			::IntersectRect(&rect, &rect, lpRect);
			Rgn rgnInside;
			rgnInside.CreateRectRgnIndirect(&rect);
			Rgn rgnNew;
			rgnNew.CreateRectRgn(0, 0, 0, 0);
			rgnNew.CombineRgn(rgnOutside, rgnInside, RGN_XOR);

			HBRUSH brushOld = NULL;
			CBrush brushHalftone;
			if(brush == NULL)
				brushHalftone = brush = DCHandle::GetHalftoneBrush();
			if(brushLast == NULL)
				brushLast = brush;

			Rgn rgnLast;
			Rgn rgnUpdate;
			if(lpRectLast != NULL)
			{
				// find difference between new region and old region
				rgnLast.CreateRectRgn(0, 0, 0, 0);
				rgnOutside.SetRectRgn(lpRectLast->left, lpRectLast->top, lpRectLast->right, lpRectLast->bottom);
				rect = *lpRectLast;
				::InflateRect(&rect, -sizeLast.cx, -sizeLast.cy);
				::IntersectRect(&rect, &rect, lpRectLast);
				rgnInside.SetRectRgn(rect.left, rect.top, rect.right, rect.bottom);
				rgnLast.CombineRgn(rgnOutside, rgnInside, RGN_XOR);

				// only diff them if brushes are the same
				if(brush == brushLast)
				{
					rgnUpdate.CreateRectRgn(0, 0, 0, 0);
					rgnUpdate.CombineRgn(rgnLast, rgnNew, RGN_XOR);
				}
			}
			if(brush != brushLast && lpRectLast != NULL)
			{
				// brushes are different -- erase old region first
				SelectClipRgn(rgnLast);
				GetClipBox(&rect);
				brushOld = SelectBrush(brushLast);
				PatBlt(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, PATINVERT);
				SelectBrush(brushOld);
				brushOld = NULL;
			}

			// draw into the update/new region
			SelectClipRgn(rgnUpdate.IsNull() ? rgnNew : rgnUpdate);
			GetClipBox(&rect);
			brushOld = SelectBrush(brush);
			PatBlt(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, PATINVERT);

			// cleanup DC
			if(brushOld != NULL)
				SelectBrush(brushOld);
			SelectClipRgn(NULL);
		}

		void FillSolidRect(LPCRECT lpRect, COLORREF clr)
		{
			ASSERT(hdc_ != NULL);

			COLORREF clrOld = ::SetBkColor(hdc_, clr);
			ASSERT(clrOld != CLR_INVALID);
			if(clrOld != CLR_INVALID)
			{
				::ExtTextOut(hdc_, 0, 0, ETO_OPAQUE, lpRect, NULL, 0, NULL);
				::SetBkColor(hdc_, clrOld);
			}
		}

		void FillSolidRect(int x, int y, int cx, int cy, COLORREF clr)
		{
			ASSERT(hdc_ != NULL);

			RECT rect = { x, y, x + cx, y + cy };
			FillSolidRect(&rect, clr);
		}

		void Draw3dRect(LPCRECT lpRect, COLORREF clrTopLeft, COLORREF clrBottomRight)
		{
			Draw3dRect(lpRect->left, lpRect->top, lpRect->right - lpRect->left,
				lpRect->bottom - lpRect->top, clrTopLeft, clrBottomRight);
		}

		void Draw3dRect(int x, int y, int cx, int cy, COLORREF clrTopLeft, COLORREF clrBottomRight)
		{
			FillSolidRect(x, y, cx - 1, 1, clrTopLeft);
			FillSolidRect(x, y, 1, cy - 1, clrTopLeft);
			FillSolidRect(x + cx, y, -1, cy, clrBottomRight);
			FillSolidRect(x, y + cy, cx, -1, clrBottomRight);
		}

		// DIB support
#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 410)
		int SetDIBitsToDevice(int x, int y, DWORD dwWidth, DWORD dwHeight, int xSrc, int ySrc, UINT uStartScan, UINT cScanLines, CONST VOID* lpvBits, CONST BITMAPINFO* lpbmi, UINT uColorUse)
		{
			ASSERT(hdc_ != NULL);
			return ::SetDIBitsToDevice(hdc_, x, y, dwWidth, dwHeight, xSrc, ySrc, uStartScan, cScanLines, lpvBits, lpbmi, uColorUse);
		}
#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 410)

#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
		int StretchDIBits(int x, int y, int nWidth, int nHeight, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, CONST VOID* lpvBits, CONST BITMAPINFO* lpbmi, UINT uColorUse, DWORD dwRop)
		{
			ASSERT(hdc_ != NULL);
			return ::StretchDIBits(hdc_, x, y, nWidth, nHeight, xSrc, ySrc, nSrcWidth, nSrcHeight, lpvBits, lpbmi, uColorUse, dwRop);
		}

		UINT GetDIBColorTable(UINT uStartIndex, UINT cEntries, RGBQUAD* pColors) const
		{
			ASSERT(hdc_ != NULL);
			return ::GetDIBColorTable(hdc_, uStartIndex, cEntries, pColors);
		}

		UINT SetDIBColorTable(UINT uStartIndex, UINT cEntries, CONST RGBQUAD* pColors)
		{
			ASSERT(hdc_ != NULL);
			return ::SetDIBColorTable(hdc_, uStartIndex, cEntries, pColors);
		}
#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)

		// OpenGL support
#if !defined(_ATL_NO_OPENGL) && !defined(_WIN32_WCE)
		int ChoosePixelFormat(CONST PIXELFORMATDESCRIPTOR* ppfd)
		{
			ASSERT(hdc_ != NULL);
			return ::ChoosePixelFormat(hdc_, ppfd);
		}

		int DescribePixelFormat(int iPixelFormat, UINT nBytes, LPPIXELFORMATDESCRIPTOR ppfd)
		{
			ASSERT(hdc_ != NULL);
			return ::DescribePixelFormat(hdc_, iPixelFormat, nBytes, ppfd);
		}

		int GetPixelFormat() const
		{
			ASSERT(hdc_ != NULL);
			return ::GetPixelFormat(hdc_);
		}

		BOOL SetPixelFormat(int iPixelFormat, CONST PIXELFORMATDESCRIPTOR* ppfd)
		{
			ASSERT(hdc_ != NULL);
			return ::SetPixelFormat(hdc_, iPixelFormat, ppfd);
		}

		BOOL SwapBuffers()
		{
			ASSERT(hdc_ != NULL);
			return ::SwapBuffers(hdc_);
		}

		HGLRC wglCreateContext()
		{
			ASSERT(hdc_ != NULL);
			return ::wglCreateContext(hdc_);
		}

		HGLRC wglCreateLayerContext(int iLayerPlane)
		{
			ASSERT(hdc_ != NULL);
			return ::wglCreateLayerContext(hdc_, iLayerPlane);
		}

		BOOL wglMakeCurrent(HGLRC hglrc)
		{
			ASSERT(hdc_ != NULL);
			return ::wglMakeCurrent(hdc_, hglrc);
		}

		BOOL wglUseFontBitmaps(DWORD dwFirst, DWORD dwCount, DWORD listBase)
		{
			ASSERT(hdc_ != NULL);
			return ::wglUseFontBitmaps(hdc_, dwFirst, dwCount, listBase);
		}

		BOOL wglUseFontOutlines(DWORD dwFirst, DWORD dwCount, DWORD listBase, FLOAT deviation, FLOAT extrusion, int format, LPGLYPHMETRICSFLOAT lpgmf)
		{
			ASSERT(hdc_ != NULL);
			return ::wglUseFontOutlines(hdc_, dwFirst, dwCount, listBase, deviation, extrusion, format, lpgmf);
		}

		BOOL wglDescribeLayerPlane(int iPixelFormat, int iLayerPlane, UINT nBytes, LPLAYERPLANEDESCRIPTOR plpd)
		{
			ASSERT(hdc_ != NULL);
			return ::wglDescribeLayerPlane(hdc_, iPixelFormat, iLayerPlane, nBytes, plpd);
		}

		int wglSetLayerPaletteEntries(int iLayerPlane, int iStart, int cEntries, CONST COLORREF* pclr)
		{
			ASSERT(hdc_ != NULL);
			return ::wglSetLayerPaletteEntries(hdc_, iLayerPlane, iStart, cEntries, pclr);
		}

		int wglGetLayerPaletteEntries(int iLayerPlane, int iStart, int cEntries, COLORREF* pclr)
		{
			ASSERT(hdc_ != NULL);
			return ::wglGetLayerPaletteEntries(hdc_, iLayerPlane, iStart, cEntries, pclr);
		}

		BOOL wglRealizeLayerPalette(int iLayerPlane, BOOL bRealize)
		{
			ASSERT(hdc_ != NULL);
			return ::wglRealizeLayerPalette(hdc_, iLayerPlane, bRealize);
		}

		BOOL wglSwapLayerBuffers(UINT uPlanes)
		{
			ASSERT(hdc_ != NULL);
			return ::wglSwapLayerBuffers(hdc_, uPlanes);
		}
#endif // !defined(_ATL_NO_OPENGL) && !defined(_WIN32_WCE)

		// New for Windows 2000 only
#if (_WIN32_WINNT >= 0x0500)
		COLORREF GetDCPenColor() const
		{
			ASSERT(hdc_ != NULL);
			return ::GetDCPenColor(hdc_);
		}

		COLORREF SetDCPenColor(COLORREF clr)
		{
			ASSERT(hdc_ != NULL);
			return ::SetDCPenColor(hdc_, clr);
		}

		COLORREF GetDCBrushColor() const
		{
			ASSERT(hdc_ != NULL);
			return ::GetDCBrushColor(hdc_);
		}

		COLORREF SetDCBrushColor(COLORREF clr)
		{
			ASSERT(hdc_ != NULL);
			return ::SetDCBrushColor(hdc_, clr);
		}

#ifndef _WIN32_WCE
		DWORD GetFontUnicodeRanges(LPGLYPHSET lpgs) const
		{
			ASSERT(hdc_ != NULL);
			return ::GetFontUnicodeRanges(hdc_, lpgs);
		}
#endif // !_WIN32_WCE

		DWORD GetGlyphIndices(LPCTSTR lpstr, int cch, LPWORD pgi, DWORD dwFlags) const
		{
			ASSERT(hdc_ != NULL);
			return ::GetGlyphIndices(hdc_, lpstr, cch, pgi, dwFlags);
		}

		BOOL GetTextExtentPointI(LPWORD pgiIn, int cgi, LPSIZE lpSize) const
		{
			ASSERT(hdc_ != NULL);
			return ::GetTextExtentPointI(hdc_, pgiIn, cgi, lpSize);
		}

		BOOL GetTextExtentExPointI(LPWORD pgiIn, int cgi, int nMaxExtent, LPINT lpnFit, LPINT alpDx, LPSIZE lpSize) const
		{
			ASSERT(hdc_ != NULL);
			return ::GetTextExtentExPointI(hdc_, pgiIn, cgi, nMaxExtent, lpnFit, alpDx, lpSize);
		}

		BOOL GetCharWidthI(UINT giFirst, UINT cgi, LPWORD pgi, LPINT lpBuffer) const
		{
			ASSERT(hdc_ != NULL);
			return ::GetCharWidthI(hdc_, giFirst, cgi, pgi, lpBuffer);
		}

		BOOL GetCharABCWidthsI(UINT giFirst, UINT cgi, LPWORD pgi, LPABC lpabc) const
		{
			ASSERT(hdc_ != NULL);
			return ::GetCharABCWidthsI(hdc_, giFirst, cgi, pgi, lpabc);
		}
#endif // (_WIN32_WINNT >= 0x0500)

		// New for Windows 2000 and Windows 98
#if (WINVER >= 0x0500) && !defined(_WIN32_WCE)
		BOOL ColorCorrectPalette(HPALETTE hPalette, DWORD dwFirstEntry, DWORD dwNumOfEntries)
		{
			ASSERT(hdc_ != NULL);
			return ::ColorCorrectPalette(hdc_, hPalette, dwFirstEntry, dwNumOfEntries);
		}
#endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE)
	};

	typedef DCT<false>   DCHandle;
	typedef DCT<true>    DC;


	/////////////////////////////////////////////////////////////////////


	class PaintDC : public DC
	{
	public:
		// Data members
		HWND hwnd_;
		PAINTSTRUCT ps_;

		// Constructor/destructor
		PaintDC(HWND hWnd)
		{
			ASSERT(::IsWindow(hWnd) == TRUE);
			hwnd_ = hWnd;
			hdc_ = ::BeginPaint(hWnd, &ps_);
		}
		
		RECT RectPaint()
		{
			return ps_.rcPaint;
		}

		~PaintDC()
		{
			ASSERT(hdc_ != NULL);
			ASSERT(::IsWindow(hwnd_) == TRUE);
			::EndPaint(hwnd_, &ps_);
			Detach();
		}
	};

	class NcPaintDC : public DC
	{
	public:
		NcPaintDC(HWND hwnd, HRGN hrgn)
			: hwnd_(hwnd)
		{
			hdc_ = GetDCEx(hwnd_, hrgn, DCX_WINDOW | DCX_INTERSECTRGN);
		}

		~NcPaintDC()
		{
			ReleaseDC(hwnd_, Detach());
		}

	private:
		HWND hwnd_;
	};

	class ClientDC : public DC
	{
	public:
		// Data members
		HWND hwnd_;

		// Constructor/destructor
		ClientDC(HWND hWnd)
		{
			ASSERT(hWnd == NULL || ::IsWindow(hWnd));
			hwnd_ = hWnd;
			hdc_ = ::GetDC(hWnd);
		}

		~ClientDC()
		{
			ASSERT(hdc_ != NULL);
			::ReleaseDC(hwnd_, Detach());
		}
	};

	class WindowDC : public DC
	{
	public:
		// Data members
		HWND m_hWnd;

		// Constructor/destructor
		WindowDC(HWND hWnd)
		{
			ASSERT(hWnd == NULL || ::IsWindow(hWnd));
			m_hWnd = hWnd;
			hdc_ = ::GetWindowDC(hWnd);
		}

		~WindowDC()
		{
			ASSERT(hdc_ != NULL);
			::ReleaseDC(m_hWnd, Detach());
		}
	};

	class MemoryDC : public DC
	{
	public:
		// Data members
		HDC origdc_;
		RECT rcpaint_;
		Bitmap bmp_;
		HBITMAP oldbmp_;

		// Constructor/destructor
		MemoryDC(HDC dc, RECT& rcPaint) : origdc_(dc), oldbmp_(NULL)
		{
			rcpaint_ = rcPaint;
			CreateCompatibleDC(origdc_);
			ASSERT(hdc_ != NULL);
			bmp_.CreateCompatibleBitmap(origdc_, rcpaint_.right - rcpaint_.left, rcpaint_.bottom - rcpaint_.top);
			ASSERT(bmp_.bitmap_ != NULL);
			oldbmp_ = SelectBitmap(bmp_);
			SetViewportOrg(-rcpaint_.left, -rcpaint_.top);
		}

		~MemoryDC()
		{
			::BitBlt(origdc_, rcpaint_.left, rcpaint_.top, rcpaint_.right - rcpaint_.left, rcpaint_.bottom - rcpaint_.top, hdc_, rcpaint_.left, rcpaint_.top, SRCCOPY);
			SelectBitmap(oldbmp_);
		}
	};


	///////////////////////////////////////////////////////////////////////////////
	// Enhanced metafile support

#ifndef _WIN32_WCE

	class EnhMetaFileInfo
	{
	public:
		// Data members
		HENHMETAFILE hemf_;
		BYTE* m_pBits;
		TCHAR* m_pDesc;
		ENHMETAHEADER m_header;
		PIXELFORMATDESCRIPTOR m_pfd;

		// Constructor/destructor
		EnhMetaFileInfo(HENHMETAFILE hEMF) : m_pBits(NULL), m_pDesc(NULL), hemf_(hEMF)
		{ }

		~EnhMetaFileInfo()
		{
			delete [] m_pBits;
			delete [] m_pDesc;
		}

		// Operations
// 		BYTE* GetEnhMetaFileBits()
// 		{
// 			ASSERT(hemf_ != NULL);
// 			UINT nBytes = ::GetEnhMetaFileBits(hemf_, 0, NULL);
// 			delete [] m_pBits;
// 			m_pBits = NULL;
// 			ATLTRY(m_pBits = new BYTE[nBytes]);
// 			if (m_pBits != NULL)
// 				::GetEnhMetaFileBits(hemf_, nBytes, m_pBits);
// 			return m_pBits;
// 		}

// 		LPTSTR GetEnhMetaFileDescription()
// 		{
// 			ASSERT(hemf_ != NULL);
// 			UINT nLen = ::GetEnhMetaFileDescription(hemf_, 0, NULL);
// 			delete [] m_pDesc;
// 			m_pDesc = NULL;
// 			ATLTRY(m_pDesc = new TCHAR[nLen]);
// 			if (m_pDesc != NULL)
// 				nLen = ::GetEnhMetaFileDescription(hemf_, nLen, m_pDesc);
// 			return m_pDesc;
// 		}

		ENHMETAHEADER* GetEnhMetaFileHeader()
		{
			ASSERT(hemf_ != NULL);
			memset(&m_header, 0, sizeof(m_header));
			m_header.iType = EMR_HEADER;
			m_header.nSize = sizeof(ENHMETAHEADER);
			UINT n = ::GetEnhMetaFileHeader(hemf_, sizeof(ENHMETAHEADER), &m_header);
			return (n != 0) ? &m_header : NULL;
		}

		PIXELFORMATDESCRIPTOR* GetEnhMetaFilePixelFormat()
		{
			ASSERT(hemf_ != NULL);
			memset(&m_pfd, 0, sizeof(m_pfd));
			UINT n = ::GetEnhMetaFilePixelFormat(hemf_, sizeof(m_pfd), &m_pfd);
			return (n != 0) ? &m_pfd : NULL;
		}
	};


	template <bool bmanaged>
	class EnhMetaFileT
	{
	public:
		// Data members
		HENHMETAFILE hemf_;

		// Constructor/destructor
		EnhMetaFileT(HENHMETAFILE hEMF = NULL) : hemf_(hEMF)
		{
		}

		~EnhMetaFileT()
		{
			if(bmanaged && hemf_ != NULL)
				DeleteObject();
		}

		// Operations
		EnhMetaFileT<bmanaged>& operator =(HENHMETAFILE hEMF)
		{
			Attach(hEMF);
			return *this;
		}

		void Attach(HENHMETAFILE hEMF)
		{
			if(bmanaged && hemf_ != NULL && hemf_ != hEMF)
				DeleteObject();
			hemf_ = hEMF;
		}

		HENHMETAFILE Detach()
		{
			HENHMETAFILE hEMF = hemf_;
			hemf_ = NULL;
			return hEMF;
		}

		operator HENHMETAFILE() const { return hemf_; }

		bool IsNull() const { return (hemf_ == NULL); }

		BOOL DeleteObject()
		{
			ASSERT(hemf_ != NULL);
			BOOL bRet = ::DeleteEnhMetaFile(hemf_);
			hemf_ = NULL;
			return bRet;
		}

		UINT GetEnhMetaFileBits(UINT cbBuffer, LPBYTE lpbBuffer) const
		{
			ASSERT(hemf_ != NULL);
			return ::GetEnhMetaFileBits(hemf_, cbBuffer, lpbBuffer);
		}

		UINT GetEnhMetaFileDescription(UINT cchBuffer, LPTSTR lpszDescription) const
		{
			ASSERT(hemf_ != NULL);
			return ::GetEnhMetaFileDescription(hemf_, cchBuffer, lpszDescription);
		}

		UINT GetEnhMetaFileHeader(LPENHMETAHEADER lpemh) const
		{
			ASSERT(hemf_ != NULL);
			lpemh->iType = EMR_HEADER;
			lpemh->nSize = sizeof(ENHMETAHEADER);
			return ::GetEnhMetaFileHeader(hemf_, sizeof(ENHMETAHEADER), lpemh);
		}

		UINT GetEnhMetaFilePaletteEntries(UINT cEntries, LPPALETTEENTRY lppe) const
		{
			ASSERT(hemf_ != NULL);
			return ::GetEnhMetaFilePaletteEntries(hemf_, cEntries, lppe);
		}

		UINT GetEnhMetaFilePixelFormat(DWORD cbBuffer, PIXELFORMATDESCRIPTOR* ppfd) const
		{
			ASSERT(hemf_ != NULL);
			return ::GetEnhMetaFilePixelFormat(hemf_, cbBuffer, ppfd);
		}
	};

	typedef EnhMetaFileT<false>   EnhMetaFileHandle;
	typedef EnhMetaFileT<true>    EnhMetaFile;


	class EnhMetaFileDC : public DC
	{
	public:
		// Constructor/destructor
		EnhMetaFileDC()
		{
		}

		EnhMetaFileDC(HDC hdc, LPCRECT lpRect)
		{
			Create(hdc, NULL, lpRect, NULL);
			ASSERT(hdc_ != NULL);
		}

		EnhMetaFileDC(HDC hdcRef, LPCTSTR lpFilename, LPCRECT lpRect, LPCTSTR lpDescription)
		{
			Create(hdcRef, lpFilename, lpRect, lpDescription);
			ASSERT(hdc_ != NULL);
		}

		~EnhMetaFileDC()
		{
			HENHMETAFILE hEMF = Close();
			if (hEMF != NULL)
				::DeleteEnhMetaFile(hEMF);
		}

		// Operations
		void Create(HDC hdcRef, LPCTSTR lpFilename, LPCRECT lpRect, LPCTSTR lpDescription)
		{
			ASSERT(hdc_ == NULL);
			hdc_ = ::CreateEnhMetaFile(hdcRef, lpFilename, lpRect, lpDescription);
		}

		HENHMETAFILE Close()
		{
			HENHMETAFILE hEMF = NULL;
			if (hdc_ != NULL)
			{
				hEMF = ::CloseEnhMetaFile(hdc_);
				hdc_ = NULL;
			}
			return hEMF;
		}
	};

#endif // !_WIN32_WCE
}

#endif	// UIWIN_GDI_GDIOBJ_H_